xref: /onnv-gate/usr/src/uts/common/os/streamio.c (revision 898:64b2a371a6bd)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
230Sstevel@tonic-gate /*	  All Rights Reserved  	*/
240Sstevel@tonic-gate 
250Sstevel@tonic-gate 
260Sstevel@tonic-gate /*
270Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
280Sstevel@tonic-gate  * Use is subject to license terms.
290Sstevel@tonic-gate  */
300Sstevel@tonic-gate 
310Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
320Sstevel@tonic-gate 
330Sstevel@tonic-gate #include <sys/types.h>
340Sstevel@tonic-gate #include <sys/sysmacros.h>
350Sstevel@tonic-gate #include <sys/param.h>
360Sstevel@tonic-gate #include <sys/errno.h>
370Sstevel@tonic-gate #include <sys/signal.h>
380Sstevel@tonic-gate #include <sys/stat.h>
390Sstevel@tonic-gate #include <sys/proc.h>
400Sstevel@tonic-gate #include <sys/cred.h>
410Sstevel@tonic-gate #include <sys/user.h>
420Sstevel@tonic-gate #include <sys/vnode.h>
430Sstevel@tonic-gate #include <sys/file.h>
440Sstevel@tonic-gate #include <sys/stream.h>
450Sstevel@tonic-gate #include <sys/strsubr.h>
460Sstevel@tonic-gate #include <sys/stropts.h>
470Sstevel@tonic-gate #include <sys/tihdr.h>
480Sstevel@tonic-gate #include <sys/var.h>
490Sstevel@tonic-gate #include <sys/poll.h>
500Sstevel@tonic-gate #include <sys/termio.h>
510Sstevel@tonic-gate #include <sys/ttold.h>
520Sstevel@tonic-gate #include <sys/systm.h>
530Sstevel@tonic-gate #include <sys/uio.h>
540Sstevel@tonic-gate #include <sys/cmn_err.h>
550Sstevel@tonic-gate #include <sys/sad.h>
560Sstevel@tonic-gate #include <sys/priocntl.h>
570Sstevel@tonic-gate #include <sys/jioctl.h>
580Sstevel@tonic-gate #include <sys/procset.h>
590Sstevel@tonic-gate #include <sys/session.h>
600Sstevel@tonic-gate #include <sys/kmem.h>
610Sstevel@tonic-gate #include <sys/filio.h>
620Sstevel@tonic-gate #include <sys/vtrace.h>
630Sstevel@tonic-gate #include <sys/debug.h>
640Sstevel@tonic-gate #include <sys/strredir.h>
650Sstevel@tonic-gate #include <sys/fs/fifonode.h>
660Sstevel@tonic-gate #include <sys/fs/snode.h>
670Sstevel@tonic-gate #include <sys/strlog.h>
680Sstevel@tonic-gate #include <sys/strsun.h>
690Sstevel@tonic-gate #include <sys/project.h>
700Sstevel@tonic-gate #include <sys/kbio.h>
710Sstevel@tonic-gate #include <sys/msio.h>
720Sstevel@tonic-gate #include <sys/tty.h>
730Sstevel@tonic-gate #include <sys/ptyvar.h>
740Sstevel@tonic-gate #include <sys/vuid_event.h>
750Sstevel@tonic-gate #include <sys/modctl.h>
760Sstevel@tonic-gate #include <sys/sunddi.h>
770Sstevel@tonic-gate #include <sys/sunldi_impl.h>
780Sstevel@tonic-gate #include <sys/autoconf.h>
790Sstevel@tonic-gate #include <sys/policy.h>
800Sstevel@tonic-gate 
810Sstevel@tonic-gate /*
820Sstevel@tonic-gate  * what is mblk_pull_len?
830Sstevel@tonic-gate  *
840Sstevel@tonic-gate  * If a streams message consists of many short messages,
850Sstevel@tonic-gate  * a performance degradation occurs from copyout overhead.
860Sstevel@tonic-gate  * To decrease the per mblk overhead, messages that are
870Sstevel@tonic-gate  * likely to consist of many small mblks are pulled up into
880Sstevel@tonic-gate  * one continuous chunk of memory.
890Sstevel@tonic-gate  *
900Sstevel@tonic-gate  * To avoid the processing overhead of examining every
910Sstevel@tonic-gate  * mblk, a quick heuristic is used. If the first mblk in
920Sstevel@tonic-gate  * the message is shorter than mblk_pull_len, it is likely
930Sstevel@tonic-gate  * that the rest of the mblk will be short.
940Sstevel@tonic-gate  *
950Sstevel@tonic-gate  * This heuristic was decided upon after performance tests
960Sstevel@tonic-gate  * indicated that anything more complex slowed down the main
970Sstevel@tonic-gate  * code path.
980Sstevel@tonic-gate  */
990Sstevel@tonic-gate #define	MBLK_PULL_LEN 64
1000Sstevel@tonic-gate uint32_t mblk_pull_len = MBLK_PULL_LEN;
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate /*
1030Sstevel@tonic-gate  * The sgttyb_handling flag controls the handling of the old BSD
1040Sstevel@tonic-gate  * TIOCGETP, TIOCSETP, and TIOCSETN ioctls as follows:
1050Sstevel@tonic-gate  *
1060Sstevel@tonic-gate  * 0 - Emit no warnings at all and retain old, broken behavior.
1070Sstevel@tonic-gate  * 1 - Emit no warnings and silently handle new semantics.
1080Sstevel@tonic-gate  * 2 - Send cmn_err(CE_NOTE) when either TIOCSETP or TIOCSETN is used
1090Sstevel@tonic-gate  *     (once per system invocation).  Handle with new semantics.
1100Sstevel@tonic-gate  * 3 - Send SIGSYS when any TIOCGETP, TIOCSETP, or TIOCSETN call is
1110Sstevel@tonic-gate  *     made (so that offenders drop core and are easy to debug).
1120Sstevel@tonic-gate  *
1130Sstevel@tonic-gate  * The "new semantics" are that TIOCGETP returns B38400 for
1140Sstevel@tonic-gate  * sg_[io]speed if the corresponding value is over B38400, and that
1150Sstevel@tonic-gate  * TIOCSET[PN] accept B38400 in these cases to mean "retain current
1160Sstevel@tonic-gate  * bit rate."
1170Sstevel@tonic-gate  */
1180Sstevel@tonic-gate int sgttyb_handling = 1;
1190Sstevel@tonic-gate static boolean_t sgttyb_complaint;
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate /* don't push drcompat module by default on Style-2 streams */
1220Sstevel@tonic-gate static int push_drcompat = 0;
1230Sstevel@tonic-gate 
1240Sstevel@tonic-gate /*
1250Sstevel@tonic-gate  * id value used to distinguish between different ioctl messages
1260Sstevel@tonic-gate  */
1270Sstevel@tonic-gate static uint32_t ioc_id;
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate static void putback(struct stdata *, queue_t *, mblk_t *, int);
1300Sstevel@tonic-gate static void strcleanall(struct vnode *);
1310Sstevel@tonic-gate static int strwsrv(queue_t *);
1320Sstevel@tonic-gate 
1330Sstevel@tonic-gate /*
1340Sstevel@tonic-gate  * qinit and module_info structures for stream head read and write queues
1350Sstevel@tonic-gate  */
1360Sstevel@tonic-gate struct module_info strm_info = { 0, "strrhead", 0, INFPSZ, STRHIGH, STRLOW };
1370Sstevel@tonic-gate struct module_info stwm_info = { 0, "strwhead", 0, 0, 0, 0 };
1380Sstevel@tonic-gate struct qinit strdata = { strrput, NULL, NULL, NULL, NULL, &strm_info };
1390Sstevel@tonic-gate struct qinit stwdata = { NULL, strwsrv, NULL, NULL, NULL, &stwm_info };
1400Sstevel@tonic-gate struct module_info fiform_info = { 0, "fifostrrhead", 0, PIPE_BUF, FIFOHIWAT,
1410Sstevel@tonic-gate     FIFOLOWAT };
1420Sstevel@tonic-gate struct module_info fifowm_info = { 0, "fifostrwhead", 0, 0, 0, 0 };
1430Sstevel@tonic-gate struct qinit fifo_strdata = { strrput, NULL, NULL, NULL, NULL, &fiform_info };
1440Sstevel@tonic-gate struct qinit fifo_stwdata = { NULL, strwsrv, NULL, NULL, NULL, &fifowm_info };
1450Sstevel@tonic-gate 
1460Sstevel@tonic-gate extern kmutex_t	strresources;	/* protects global resources */
1470Sstevel@tonic-gate extern kmutex_t muxifier;	/* single-threads multiplexor creation */
1480Sstevel@tonic-gate kmutex_t sad_lock;		/* protects sad drivers autopush */
1490Sstevel@tonic-gate 
1500Sstevel@tonic-gate static boolean_t msghasdata(mblk_t *bp);
1510Sstevel@tonic-gate #define	msgnodata(bp) (!msghasdata(bp))
1520Sstevel@tonic-gate 
1530Sstevel@tonic-gate /*
1540Sstevel@tonic-gate  * Stream head locking notes:
1550Sstevel@tonic-gate  *	There are four monitors associated with the stream head:
1560Sstevel@tonic-gate  *	1. v_stream monitor: in stropen() and strclose() v_lock
1570Sstevel@tonic-gate  *		is held while the association of vnode and stream
1580Sstevel@tonic-gate  *		head is established or tested for.
1590Sstevel@tonic-gate  *	2. open/close/push/pop monitor: sd_lock is held while each
1600Sstevel@tonic-gate  *		thread bids for exclusive access to this monitor
1610Sstevel@tonic-gate  *		for opening or closing a stream.  In addition, this
1620Sstevel@tonic-gate  *		monitor is entered during pushes and pops.  This
1630Sstevel@tonic-gate  *		guarantees that during plumbing operations there
1640Sstevel@tonic-gate  *		is only one thread trying to change the plumbing.
1650Sstevel@tonic-gate  *		Any other threads present in the stream are only
1660Sstevel@tonic-gate  *		using the plumbing.
1670Sstevel@tonic-gate  *	3. read/write monitor: in the case of read, a thread holds
1680Sstevel@tonic-gate  *		sd_lock while trying to get data from the stream
1690Sstevel@tonic-gate  *		head queue.  if there is none to fulfill a read
1700Sstevel@tonic-gate  *		request, it sets RSLEEP and calls cv_wait_sig() down
1710Sstevel@tonic-gate  *		in strwaitq() to await the arrival of new data.
1720Sstevel@tonic-gate  *		when new data arrives in strrput(), sd_lock is acquired
1730Sstevel@tonic-gate  *		before testing for RSLEEP and calling cv_broadcast().
1740Sstevel@tonic-gate  *		the behavior of strwrite(), strwsrv(), and WSLEEP
1750Sstevel@tonic-gate  *		mirror this.
1760Sstevel@tonic-gate  *	4. ioctl monitor: sd_lock is gotten to ensure that only one
1770Sstevel@tonic-gate  *		thread is doing an ioctl at a time.
1780Sstevel@tonic-gate  */
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate static int
1810Sstevel@tonic-gate push_mod(queue_t *qp, dev_t *devp, struct stdata *stp, const char *name,
1820Sstevel@tonic-gate     int anchor, cred_t *crp)
1830Sstevel@tonic-gate {
1840Sstevel@tonic-gate 	int error;
1850Sstevel@tonic-gate 	fmodsw_impl_t *fp;
1860Sstevel@tonic-gate 
1870Sstevel@tonic-gate 	if (stp->sd_flag & (STRHUP|STRDERR|STWRERR)) {
1880Sstevel@tonic-gate 		error = (stp->sd_flag & STRHUP) ? ENXIO : EIO;
1890Sstevel@tonic-gate 		return (error);
1900Sstevel@tonic-gate 	}
1910Sstevel@tonic-gate 	if (stp->sd_pushcnt >= nstrpush) {
1920Sstevel@tonic-gate 		return (EINVAL);
1930Sstevel@tonic-gate 	}
1940Sstevel@tonic-gate 
1950Sstevel@tonic-gate 	if ((fp = fmodsw_find(name, FMODSW_HOLD | FMODSW_LOAD)) == NULL) {
1960Sstevel@tonic-gate 		stp->sd_flag |= STREOPENFAIL;
1970Sstevel@tonic-gate 		return (EINVAL);
1980Sstevel@tonic-gate 	}
1990Sstevel@tonic-gate 
2000Sstevel@tonic-gate 	/*
2010Sstevel@tonic-gate 	 * push new module and call its open routine via qattach
2020Sstevel@tonic-gate 	 */
2030Sstevel@tonic-gate 	if ((error = qattach(qp, devp, 0, crp, fp, B_FALSE)) != 0)
2040Sstevel@tonic-gate 		return (error);
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate 	/*
2070Sstevel@tonic-gate 	 * Check to see if caller wants a STREAMS anchor
2080Sstevel@tonic-gate 	 * put at this place in the stream, and add if so.
2090Sstevel@tonic-gate 	 */
2100Sstevel@tonic-gate 	mutex_enter(&stp->sd_lock);
2110Sstevel@tonic-gate 	if (anchor == stp->sd_pushcnt)
2120Sstevel@tonic-gate 		stp->sd_anchor = stp->sd_pushcnt;
2130Sstevel@tonic-gate 	mutex_exit(&stp->sd_lock);
2140Sstevel@tonic-gate 
2150Sstevel@tonic-gate 	return (0);
2160Sstevel@tonic-gate }
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate /*
2190Sstevel@tonic-gate  * Open a stream device.
2200Sstevel@tonic-gate  */
2210Sstevel@tonic-gate int
2220Sstevel@tonic-gate stropen(vnode_t *vp, dev_t *devp, int flag, cred_t *crp)
2230Sstevel@tonic-gate {
2240Sstevel@tonic-gate 	struct stdata *stp;
2250Sstevel@tonic-gate 	queue_t *qp;
2260Sstevel@tonic-gate 	int s;
2270Sstevel@tonic-gate 	dev_t dummydev;
2280Sstevel@tonic-gate 	struct autopush *ap;
2290Sstevel@tonic-gate 	int error = 0;
2300Sstevel@tonic-gate 	ssize_t	rmin, rmax;
2310Sstevel@tonic-gate 	int cloneopen;
2320Sstevel@tonic-gate 	queue_t *brq;
2330Sstevel@tonic-gate 	major_t major;
2340Sstevel@tonic-gate 
2350Sstevel@tonic-gate #ifdef C2_AUDIT
2360Sstevel@tonic-gate 	if (audit_active)
2370Sstevel@tonic-gate 		audit_stropen(vp, devp, flag, crp);
2380Sstevel@tonic-gate #endif
2390Sstevel@tonic-gate 
2400Sstevel@tonic-gate 	/*
2410Sstevel@tonic-gate 	 * If the stream already exists, wait for any open in progress
2420Sstevel@tonic-gate 	 * to complete, then call the open function of each module and
2430Sstevel@tonic-gate 	 * driver in the stream.  Otherwise create the stream.
2440Sstevel@tonic-gate 	 */
2450Sstevel@tonic-gate 	TRACE_1(TR_FAC_STREAMS_FR, TR_STROPEN, "stropen:%p", vp);
2460Sstevel@tonic-gate retry:
2470Sstevel@tonic-gate 	mutex_enter(&vp->v_lock);
2480Sstevel@tonic-gate 	if ((stp = vp->v_stream) != NULL) {
2490Sstevel@tonic-gate 
2500Sstevel@tonic-gate 		/*
2510Sstevel@tonic-gate 		 * Waiting for stream to be created to device
2520Sstevel@tonic-gate 		 * due to another open.
2530Sstevel@tonic-gate 		 */
2540Sstevel@tonic-gate 	    mutex_exit(&vp->v_lock);
2550Sstevel@tonic-gate 
2560Sstevel@tonic-gate 	    if (STRMATED(stp)) {
2570Sstevel@tonic-gate 		struct stdata *strmatep = stp->sd_mate;
2580Sstevel@tonic-gate 
2590Sstevel@tonic-gate 		STRLOCKMATES(stp);
2600Sstevel@tonic-gate 		if (strmatep->sd_flag & (STWOPEN|STRCLOSE|STRPLUMB)) {
2610Sstevel@tonic-gate 			if (flag & (FNDELAY|FNONBLOCK)) {
2620Sstevel@tonic-gate 				error = EAGAIN;
2630Sstevel@tonic-gate 				mutex_exit(&strmatep->sd_lock);
2640Sstevel@tonic-gate 				goto ckreturn;
2650Sstevel@tonic-gate 			}
2660Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
2670Sstevel@tonic-gate 			if (!cv_wait_sig(&strmatep->sd_monitor,
2680Sstevel@tonic-gate 			    &strmatep->sd_lock)) {
2690Sstevel@tonic-gate 				error = EINTR;
2700Sstevel@tonic-gate 				mutex_exit(&strmatep->sd_lock);
2710Sstevel@tonic-gate 				mutex_enter(&stp->sd_lock);
2720Sstevel@tonic-gate 				goto ckreturn;
2730Sstevel@tonic-gate 			}
2740Sstevel@tonic-gate 			mutex_exit(&strmatep->sd_lock);
2750Sstevel@tonic-gate 			goto retry;
2760Sstevel@tonic-gate 		}
2770Sstevel@tonic-gate 		if (stp->sd_flag & (STWOPEN|STRCLOSE|STRPLUMB)) {
2780Sstevel@tonic-gate 			if (flag & (FNDELAY|FNONBLOCK)) {
2790Sstevel@tonic-gate 				error = EAGAIN;
2800Sstevel@tonic-gate 				mutex_exit(&strmatep->sd_lock);
2810Sstevel@tonic-gate 				goto ckreturn;
2820Sstevel@tonic-gate 			}
2830Sstevel@tonic-gate 			mutex_exit(&strmatep->sd_lock);
2840Sstevel@tonic-gate 			if (!cv_wait_sig(&stp->sd_monitor, &stp->sd_lock)) {
2850Sstevel@tonic-gate 				error = EINTR;
2860Sstevel@tonic-gate 				goto ckreturn;
2870Sstevel@tonic-gate 			}
2880Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
2890Sstevel@tonic-gate 			goto retry;
2900Sstevel@tonic-gate 		}
2910Sstevel@tonic-gate 
2920Sstevel@tonic-gate 		if (stp->sd_flag & (STRDERR|STWRERR)) {
2930Sstevel@tonic-gate 			error = EIO;
2940Sstevel@tonic-gate 			mutex_exit(&strmatep->sd_lock);
2950Sstevel@tonic-gate 			goto ckreturn;
2960Sstevel@tonic-gate 		}
2970Sstevel@tonic-gate 
2980Sstevel@tonic-gate 		stp->sd_flag |= STWOPEN;
2990Sstevel@tonic-gate 		STRUNLOCKMATES(stp);
3000Sstevel@tonic-gate 	    } else {
3010Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
3020Sstevel@tonic-gate 		if (stp->sd_flag & (STWOPEN|STRCLOSE|STRPLUMB)) {
3030Sstevel@tonic-gate 			if (flag & (FNDELAY|FNONBLOCK)) {
3040Sstevel@tonic-gate 				error = EAGAIN;
3050Sstevel@tonic-gate 				goto ckreturn;
3060Sstevel@tonic-gate 			}
3070Sstevel@tonic-gate 			if (!cv_wait_sig(&stp->sd_monitor, &stp->sd_lock)) {
3080Sstevel@tonic-gate 				error = EINTR;
3090Sstevel@tonic-gate 				goto ckreturn;
3100Sstevel@tonic-gate 			}
3110Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
3120Sstevel@tonic-gate 			goto retry;  /* could be clone! */
3130Sstevel@tonic-gate 		}
3140Sstevel@tonic-gate 
3150Sstevel@tonic-gate 		if (stp->sd_flag & (STRDERR|STWRERR)) {
3160Sstevel@tonic-gate 			error = EIO;
3170Sstevel@tonic-gate 			goto ckreturn;
3180Sstevel@tonic-gate 		}
3190Sstevel@tonic-gate 
3200Sstevel@tonic-gate 		stp->sd_flag |= STWOPEN;
3210Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
3220Sstevel@tonic-gate 	    }
3230Sstevel@tonic-gate 
3240Sstevel@tonic-gate 		/*
3250Sstevel@tonic-gate 		 * Open all modules and devices down stream to notify
3260Sstevel@tonic-gate 		 * that another user is streaming.  For modules, set the
3270Sstevel@tonic-gate 		 * last argument to MODOPEN and do not pass any open flags.
3280Sstevel@tonic-gate 		 * Ignore dummydev since this is not the first open.
3290Sstevel@tonic-gate 		 */
3300Sstevel@tonic-gate 	    claimstr(stp->sd_wrq);
3310Sstevel@tonic-gate 	    qp = stp->sd_wrq;
3320Sstevel@tonic-gate 	    while (_SAMESTR(qp)) {
3330Sstevel@tonic-gate 		qp = qp->q_next;
3340Sstevel@tonic-gate 		if ((error = qreopen(_RD(qp), devp, flag, crp)) != 0)
3350Sstevel@tonic-gate 			break;
3360Sstevel@tonic-gate 	    }
3370Sstevel@tonic-gate 	    releasestr(stp->sd_wrq);
3380Sstevel@tonic-gate 	    mutex_enter(&stp->sd_lock);
3390Sstevel@tonic-gate 	    stp->sd_flag &= ~(STRHUP|STWOPEN|STRDERR|STWRERR);
3400Sstevel@tonic-gate 	    stp->sd_rerror = 0;
3410Sstevel@tonic-gate 	    stp->sd_werror = 0;
3420Sstevel@tonic-gate ckreturn:
3430Sstevel@tonic-gate 	    cv_broadcast(&stp->sd_monitor);
3440Sstevel@tonic-gate 	    mutex_exit(&stp->sd_lock);
3450Sstevel@tonic-gate 	    return (error);
3460Sstevel@tonic-gate 	}
3470Sstevel@tonic-gate 
3480Sstevel@tonic-gate 	/*
3490Sstevel@tonic-gate 	 * This vnode isn't streaming.  SPECFS already
3500Sstevel@tonic-gate 	 * checked for multiple vnodes pointing to the
3510Sstevel@tonic-gate 	 * same stream, so create a stream to the driver.
3520Sstevel@tonic-gate 	 */
3530Sstevel@tonic-gate 	qp = allocq();
3540Sstevel@tonic-gate 	stp = shalloc(qp);
3550Sstevel@tonic-gate 
3560Sstevel@tonic-gate 	/*
3570Sstevel@tonic-gate 	 * Initialize stream head.  shalloc() has given us
3580Sstevel@tonic-gate 	 * exclusive access, and we have the vnode locked;
3590Sstevel@tonic-gate 	 * we can do whatever we want with stp.
3600Sstevel@tonic-gate 	 */
3610Sstevel@tonic-gate 	stp->sd_flag = STWOPEN;
3620Sstevel@tonic-gate 	stp->sd_siglist = NULL;
3630Sstevel@tonic-gate 	stp->sd_pollist.ph_list = NULL;
3640Sstevel@tonic-gate 	stp->sd_sigflags = 0;
3650Sstevel@tonic-gate 	stp->sd_mark = NULL;
3660Sstevel@tonic-gate 	stp->sd_closetime = STRTIMOUT;
3670Sstevel@tonic-gate 	stp->sd_sidp = NULL;
3680Sstevel@tonic-gate 	stp->sd_pgidp = NULL;
3690Sstevel@tonic-gate 	stp->sd_vnode = vp;
3700Sstevel@tonic-gate 	stp->sd_rerror = 0;
3710Sstevel@tonic-gate 	stp->sd_werror = 0;
3720Sstevel@tonic-gate 	stp->sd_wroff = 0;
373*898Skais 	stp->sd_tail = 0;
3740Sstevel@tonic-gate 	stp->sd_iocblk = NULL;
3750Sstevel@tonic-gate 	stp->sd_pushcnt = 0;
3760Sstevel@tonic-gate 	stp->sd_qn_minpsz = 0;
3770Sstevel@tonic-gate 	stp->sd_qn_maxpsz = INFPSZ - 1;	/* used to check for initialization */
3780Sstevel@tonic-gate 	stp->sd_maxblk = INFPSZ;
3790Sstevel@tonic-gate 	qp->q_ptr = _WR(qp)->q_ptr = stp;
3800Sstevel@tonic-gate 	STREAM(qp) = STREAM(_WR(qp)) = stp;
3810Sstevel@tonic-gate 	vp->v_stream = stp;
3820Sstevel@tonic-gate 	mutex_exit(&vp->v_lock);
3830Sstevel@tonic-gate 	if (vp->v_type == VFIFO) {
3840Sstevel@tonic-gate 		stp->sd_flag |= OLDNDELAY;
3850Sstevel@tonic-gate 		/*
3860Sstevel@tonic-gate 		 * This means, both for pipes and fifos
3870Sstevel@tonic-gate 		 * strwrite will send SIGPIPE if the other
3880Sstevel@tonic-gate 		 * end is closed. For putmsg it depends
3890Sstevel@tonic-gate 		 * on whether it is a XPG4_2 application
3900Sstevel@tonic-gate 		 * or not
3910Sstevel@tonic-gate 		 */
3920Sstevel@tonic-gate 		stp->sd_wput_opt = SW_SIGPIPE;
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate 		/* setq might sleep in kmem_alloc - avoid holding locks. */
3950Sstevel@tonic-gate 		setq(qp, &fifo_strdata, &fifo_stwdata, NULL, QMTSAFE,
3960Sstevel@tonic-gate 		    SQ_CI|SQ_CO, B_FALSE);
3970Sstevel@tonic-gate 
3980Sstevel@tonic-gate 		set_qend(qp);
399560Smeem 		stp->sd_strtab = fifo_getinfo();
4000Sstevel@tonic-gate 		_WR(qp)->q_nfsrv = _WR(qp);
4010Sstevel@tonic-gate 		qp->q_nfsrv = qp;
4020Sstevel@tonic-gate 		/*
4030Sstevel@tonic-gate 		 * Wake up others that are waiting for stream to be created.
4040Sstevel@tonic-gate 		 */
4050Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
4060Sstevel@tonic-gate 		/*
4070Sstevel@tonic-gate 		 * nothing is be pushed on stream yet, so
4080Sstevel@tonic-gate 		 * optimized stream head packetsizes are just that
4090Sstevel@tonic-gate 		 * of the read queue
4100Sstevel@tonic-gate 		 */
4110Sstevel@tonic-gate 		stp->sd_qn_minpsz = qp->q_minpsz;
4120Sstevel@tonic-gate 		stp->sd_qn_maxpsz = qp->q_maxpsz;
4130Sstevel@tonic-gate 		stp->sd_flag &= ~STWOPEN;
4140Sstevel@tonic-gate 		goto fifo_opendone;
4150Sstevel@tonic-gate 	}
4160Sstevel@tonic-gate 	/* setq might sleep in kmem_alloc - avoid holding locks. */
4170Sstevel@tonic-gate 	setq(qp, &strdata, &stwdata, NULL, QMTSAFE, SQ_CI|SQ_CO, B_FALSE);
4180Sstevel@tonic-gate 
4190Sstevel@tonic-gate 	set_qend(qp);
4200Sstevel@tonic-gate 
4210Sstevel@tonic-gate 	/*
4220Sstevel@tonic-gate 	 * Open driver and create stream to it (via qattach).
4230Sstevel@tonic-gate 	 */
4240Sstevel@tonic-gate 	cloneopen = (getmajor(*devp) == clone_major);
4250Sstevel@tonic-gate 	if ((error = qattach(qp, devp, flag, crp, NULL, B_FALSE)) != 0) {
4260Sstevel@tonic-gate 		mutex_enter(&vp->v_lock);
4270Sstevel@tonic-gate 		vp->v_stream = NULL;
4280Sstevel@tonic-gate 		mutex_exit(&vp->v_lock);
4290Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
4300Sstevel@tonic-gate 		cv_broadcast(&stp->sd_monitor);
4310Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
4320Sstevel@tonic-gate 		freeq(_RD(qp));
4330Sstevel@tonic-gate 		shfree(stp);
4340Sstevel@tonic-gate 		return (error);
4350Sstevel@tonic-gate 	}
4360Sstevel@tonic-gate 	/*
4370Sstevel@tonic-gate 	 * Set sd_strtab after open in order to handle clonable drivers
4380Sstevel@tonic-gate 	 */
4390Sstevel@tonic-gate 	stp->sd_strtab = STREAMSTAB(getmajor(*devp));
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate 	/*
4420Sstevel@tonic-gate 	 * Historical note: dummydev used to be be prior to the initial
4430Sstevel@tonic-gate 	 * open (via qattach above), which made the value seen
4440Sstevel@tonic-gate 	 * inconsistent between an I_PUSH and an autopush of a module.
4450Sstevel@tonic-gate 	 */
4460Sstevel@tonic-gate 	dummydev = *devp;
4470Sstevel@tonic-gate 
4480Sstevel@tonic-gate 	/*
4490Sstevel@tonic-gate 	 * For clone open of old style (Q not associated) network driver,
4500Sstevel@tonic-gate 	 * push DRMODNAME module to handle DL_ATTACH/DL_DETACH
4510Sstevel@tonic-gate 	 */
4520Sstevel@tonic-gate 	brq = _RD(_WR(qp)->q_next);
4530Sstevel@tonic-gate 	major = getmajor(*devp);
4540Sstevel@tonic-gate 	if (push_drcompat && cloneopen && NETWORK_DRV(major) &&
4550Sstevel@tonic-gate 	    ((brq->q_flag & _QASSOCIATED) == 0)) {
4560Sstevel@tonic-gate 		if (push_mod(qp, &dummydev, stp, DRMODNAME, 0, crp) != 0)
4570Sstevel@tonic-gate 			cmn_err(CE_WARN, "cannot push " DRMODNAME
4580Sstevel@tonic-gate 			    " streams module");
4590Sstevel@tonic-gate 	}
4600Sstevel@tonic-gate 
4610Sstevel@tonic-gate 	/*
4620Sstevel@tonic-gate 	 * check for autopush
4630Sstevel@tonic-gate 	 */
4640Sstevel@tonic-gate 	mutex_enter(&sad_lock);
4650Sstevel@tonic-gate 	ap = strphash(getemajor(*devp));
4660Sstevel@tonic-gate #define	DEVT(ap)	makedevice(ap->ap_major, ap->ap_minor)
4670Sstevel@tonic-gate #define	DEVLT(ap)	makedevice(ap->ap_major, ap->ap_lastminor)
4680Sstevel@tonic-gate 
4690Sstevel@tonic-gate 	while (ap) {
4700Sstevel@tonic-gate 		if (ap->ap_major == (getemajor(*devp))) {
4710Sstevel@tonic-gate 			if (ap->ap_type == SAP_ALL)
4720Sstevel@tonic-gate 				break;
4730Sstevel@tonic-gate 			else if ((ap->ap_type == SAP_ONE) &&
4740Sstevel@tonic-gate 			    (getminor(DEVT(ap)) == getminor(*devp)))
4750Sstevel@tonic-gate 				break;
4760Sstevel@tonic-gate 			else if (ap->ap_type == SAP_RANGE &&
4770Sstevel@tonic-gate 			    getminor(*devp) >= getminor(DEVT(ap)) &&
4780Sstevel@tonic-gate 			    getminor(*devp) <= getminor(DEVLT(ap)))
4790Sstevel@tonic-gate 				break;
4800Sstevel@tonic-gate 		}
4810Sstevel@tonic-gate 		ap = ap->ap_nextp;
4820Sstevel@tonic-gate 	}
4830Sstevel@tonic-gate 	if (ap == NULL) {
4840Sstevel@tonic-gate 		mutex_exit(&sad_lock);
4850Sstevel@tonic-gate 		goto opendone;
4860Sstevel@tonic-gate 	}
4870Sstevel@tonic-gate 	ap->ap_cnt++;
4880Sstevel@tonic-gate 	mutex_exit(&sad_lock);
4890Sstevel@tonic-gate 	for (s = 0; s < ap->ap_npush; s++) {
4900Sstevel@tonic-gate 		error = push_mod(qp, &dummydev, stp, ap->ap_list[s],
4910Sstevel@tonic-gate 		    ap->ap_anchor, crp);
4920Sstevel@tonic-gate 		if (error != 0)
4930Sstevel@tonic-gate 			break;
4940Sstevel@tonic-gate 	}
4950Sstevel@tonic-gate 	mutex_enter(&sad_lock);
4960Sstevel@tonic-gate 	if (--(ap->ap_cnt) <= 0)
4970Sstevel@tonic-gate 		ap_free(ap);
4980Sstevel@tonic-gate 	mutex_exit(&sad_lock);
4990Sstevel@tonic-gate 
5000Sstevel@tonic-gate 	/*
5010Sstevel@tonic-gate 	 * let specfs know that open failed part way through
5020Sstevel@tonic-gate 	 */
5030Sstevel@tonic-gate 
5040Sstevel@tonic-gate 	if (error) {
5050Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
5060Sstevel@tonic-gate 		stp->sd_flag |= STREOPENFAIL;
5070Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
5080Sstevel@tonic-gate 	}
5090Sstevel@tonic-gate 
5100Sstevel@tonic-gate opendone:
5110Sstevel@tonic-gate 
5120Sstevel@tonic-gate 	/*
5130Sstevel@tonic-gate 	 * Wake up others that are waiting for stream to be created.
5140Sstevel@tonic-gate 	 */
5150Sstevel@tonic-gate 	mutex_enter(&stp->sd_lock);
5160Sstevel@tonic-gate 	stp->sd_flag &= ~STWOPEN;
5170Sstevel@tonic-gate 
5180Sstevel@tonic-gate 	/*
5190Sstevel@tonic-gate 	 * As a performance concern we are caching the values of
5200Sstevel@tonic-gate 	 * q_minpsz and q_maxpsz of the module below the stream
5210Sstevel@tonic-gate 	 * head in the stream head.
5220Sstevel@tonic-gate 	 */
5230Sstevel@tonic-gate 	mutex_enter(QLOCK(stp->sd_wrq->q_next));
5240Sstevel@tonic-gate 	rmin = stp->sd_wrq->q_next->q_minpsz;
5250Sstevel@tonic-gate 	rmax = stp->sd_wrq->q_next->q_maxpsz;
5260Sstevel@tonic-gate 	mutex_exit(QLOCK(stp->sd_wrq->q_next));
5270Sstevel@tonic-gate 
5280Sstevel@tonic-gate 	/* do this processing here as a performance concern */
5290Sstevel@tonic-gate 	if (strmsgsz != 0) {
5300Sstevel@tonic-gate 		if (rmax == INFPSZ)
5310Sstevel@tonic-gate 			rmax = strmsgsz;
5320Sstevel@tonic-gate 		else
5330Sstevel@tonic-gate 			rmax = MIN(strmsgsz, rmax);
5340Sstevel@tonic-gate 	}
5350Sstevel@tonic-gate 
5360Sstevel@tonic-gate 	mutex_enter(QLOCK(stp->sd_wrq));
5370Sstevel@tonic-gate 	stp->sd_qn_minpsz = rmin;
5380Sstevel@tonic-gate 	stp->sd_qn_maxpsz = rmax;
5390Sstevel@tonic-gate 	mutex_exit(QLOCK(stp->sd_wrq));
5400Sstevel@tonic-gate 
5410Sstevel@tonic-gate fifo_opendone:
5420Sstevel@tonic-gate 	cv_broadcast(&stp->sd_monitor);
5430Sstevel@tonic-gate 	mutex_exit(&stp->sd_lock);
5440Sstevel@tonic-gate 	return (error);
5450Sstevel@tonic-gate }
5460Sstevel@tonic-gate 
5470Sstevel@tonic-gate static int strsink(queue_t *, mblk_t *);
5480Sstevel@tonic-gate static struct qinit deadrend = {
5490Sstevel@tonic-gate 	strsink, NULL, NULL, NULL, NULL, &strm_info, NULL
5500Sstevel@tonic-gate };
5510Sstevel@tonic-gate static struct qinit deadwend = {
5520Sstevel@tonic-gate 	NULL, NULL, NULL, NULL, NULL, &stwm_info, NULL
5530Sstevel@tonic-gate };
5540Sstevel@tonic-gate 
5550Sstevel@tonic-gate /*
5560Sstevel@tonic-gate  * Close a stream.
5570Sstevel@tonic-gate  * This is called from closef() on the last close of an open stream.
5580Sstevel@tonic-gate  * Strclean() will already have removed the siglist and pollist
5590Sstevel@tonic-gate  * information, so all that remains is to remove all multiplexor links
5600Sstevel@tonic-gate  * for the stream, pop all the modules (and the driver), and free the
5610Sstevel@tonic-gate  * stream structure.
5620Sstevel@tonic-gate  */
5630Sstevel@tonic-gate 
5640Sstevel@tonic-gate int
5650Sstevel@tonic-gate strclose(struct vnode *vp, int flag, cred_t *crp)
5660Sstevel@tonic-gate {
5670Sstevel@tonic-gate 	struct stdata *stp;
5680Sstevel@tonic-gate 	queue_t *qp;
5690Sstevel@tonic-gate 	int rval;
5700Sstevel@tonic-gate 	int freestp = 1;
5710Sstevel@tonic-gate 	queue_t *rmq;
5720Sstevel@tonic-gate 
5730Sstevel@tonic-gate #ifdef C2_AUDIT
5740Sstevel@tonic-gate 	if (audit_active)
5750Sstevel@tonic-gate 		audit_strclose(vp, flag, crp);
5760Sstevel@tonic-gate #endif
5770Sstevel@tonic-gate 
5780Sstevel@tonic-gate 	TRACE_1(TR_FAC_STREAMS_FR,
5790Sstevel@tonic-gate 		TR_STRCLOSE, "strclose:%p", vp);
5800Sstevel@tonic-gate 	ASSERT(vp->v_stream);
5810Sstevel@tonic-gate 
5820Sstevel@tonic-gate 	stp = vp->v_stream;
5830Sstevel@tonic-gate 	ASSERT(!(stp->sd_flag & STPLEX));
5840Sstevel@tonic-gate 	qp = stp->sd_wrq;
5850Sstevel@tonic-gate 
5860Sstevel@tonic-gate 	/*
5870Sstevel@tonic-gate 	 * Needed so that strpoll will return non-zero for this fd.
5880Sstevel@tonic-gate 	 * Note that with POLLNOERR STRHUP does still cause POLLHUP.
5890Sstevel@tonic-gate 	 */
5900Sstevel@tonic-gate 	mutex_enter(&stp->sd_lock);
5910Sstevel@tonic-gate 	stp->sd_flag |= STRHUP;
5920Sstevel@tonic-gate 	mutex_exit(&stp->sd_lock);
5930Sstevel@tonic-gate 
5940Sstevel@tonic-gate 	/*
5950Sstevel@tonic-gate 	 * Since we call pollwakeup in close() now, the poll list should
5960Sstevel@tonic-gate 	 * be empty in most cases. The only exception is the layered devices
5970Sstevel@tonic-gate 	 * (e.g. the console drivers with redirection modules pushed on top
5980Sstevel@tonic-gate 	 * of it).
5990Sstevel@tonic-gate 	 */
6000Sstevel@tonic-gate 	if (stp->sd_pollist.ph_list != NULL) {
6010Sstevel@tonic-gate 		pollwakeup(&stp->sd_pollist, POLLERR);
6020Sstevel@tonic-gate 		pollhead_clean(&stp->sd_pollist);
6030Sstevel@tonic-gate 	}
6040Sstevel@tonic-gate 	ASSERT(stp->sd_pollist.ph_list == NULL);
6050Sstevel@tonic-gate 	ASSERT(stp->sd_sidp == NULL);
6060Sstevel@tonic-gate 	ASSERT(stp->sd_pgidp == NULL);
6070Sstevel@tonic-gate 
6080Sstevel@tonic-gate 	/*
6090Sstevel@tonic-gate 	 * If the registered process or process group did not have an
6100Sstevel@tonic-gate 	 * open instance of this stream then strclean would not be
6110Sstevel@tonic-gate 	 * called. Thus at the time of closing all remaining siglist entries
6120Sstevel@tonic-gate 	 * are removed.
6130Sstevel@tonic-gate 	 */
6140Sstevel@tonic-gate 	if (stp->sd_siglist != NULL)
6150Sstevel@tonic-gate 		strcleanall(vp);
6160Sstevel@tonic-gate 
6170Sstevel@tonic-gate 	ASSERT(stp->sd_siglist == NULL);
6180Sstevel@tonic-gate 	ASSERT(stp->sd_sigflags == 0);
6190Sstevel@tonic-gate 
6200Sstevel@tonic-gate 	if (STRMATED(stp)) {
6210Sstevel@tonic-gate 		struct stdata *strmatep = stp->sd_mate;
6220Sstevel@tonic-gate 		int waited = 1;
6230Sstevel@tonic-gate 
6240Sstevel@tonic-gate 		STRLOCKMATES(stp);
6250Sstevel@tonic-gate 		while (waited) {
6260Sstevel@tonic-gate 			waited = 0;
6270Sstevel@tonic-gate 			while (stp->sd_flag & (STWOPEN|STRCLOSE|STRPLUMB)) {
6280Sstevel@tonic-gate 				mutex_exit(&strmatep->sd_lock);
6290Sstevel@tonic-gate 				cv_wait(&stp->sd_monitor, &stp->sd_lock);
6300Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
6310Sstevel@tonic-gate 				STRLOCKMATES(stp);
6320Sstevel@tonic-gate 				waited = 1;
6330Sstevel@tonic-gate 			}
6340Sstevel@tonic-gate 			while (strmatep->sd_flag &
6350Sstevel@tonic-gate 			    (STWOPEN|STRCLOSE|STRPLUMB)) {
6360Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
6370Sstevel@tonic-gate 				cv_wait(&strmatep->sd_monitor,
6380Sstevel@tonic-gate 				    &strmatep->sd_lock);
6390Sstevel@tonic-gate 				mutex_exit(&strmatep->sd_lock);
6400Sstevel@tonic-gate 				STRLOCKMATES(stp);
6410Sstevel@tonic-gate 				waited = 1;
6420Sstevel@tonic-gate 			}
6430Sstevel@tonic-gate 		}
6440Sstevel@tonic-gate 		stp->sd_flag |= STRCLOSE;
6450Sstevel@tonic-gate 		STRUNLOCKMATES(stp);
6460Sstevel@tonic-gate 	} else {
6470Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
6480Sstevel@tonic-gate 		stp->sd_flag |= STRCLOSE;
6490Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
6500Sstevel@tonic-gate 	}
6510Sstevel@tonic-gate 
6520Sstevel@tonic-gate 	ASSERT(qp->q_first == NULL);	/* No more delayed write */
6530Sstevel@tonic-gate 
6540Sstevel@tonic-gate 	/* Check if an I_LINK was ever done on this stream */
6550Sstevel@tonic-gate 	if (stp->sd_flag & STRHASLINKS) {
6560Sstevel@tonic-gate 		(void) munlinkall(stp, LINKCLOSE|LINKNORMAL, crp, &rval);
6570Sstevel@tonic-gate 	}
6580Sstevel@tonic-gate 
6590Sstevel@tonic-gate 	while (_SAMESTR(qp)) {
6600Sstevel@tonic-gate 		/*
6610Sstevel@tonic-gate 		 * Holding sd_lock prevents q_next from changing in
6620Sstevel@tonic-gate 		 * this stream.
6630Sstevel@tonic-gate 		 */
6640Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
6650Sstevel@tonic-gate 		if (!(flag & (FNDELAY|FNONBLOCK)) && (stp->sd_closetime > 0)) {
6660Sstevel@tonic-gate 
6670Sstevel@tonic-gate 			/*
6680Sstevel@tonic-gate 			 * sleep until awakened by strwsrv() or timeout
6690Sstevel@tonic-gate 			 */
6700Sstevel@tonic-gate 			for (;;) {
6710Sstevel@tonic-gate 				mutex_enter(QLOCK(qp->q_next));
6720Sstevel@tonic-gate 				if (!(qp->q_next->q_mblkcnt)) {
6730Sstevel@tonic-gate 					mutex_exit(QLOCK(qp->q_next));
6740Sstevel@tonic-gate 					break;
6750Sstevel@tonic-gate 				}
6760Sstevel@tonic-gate 				stp->sd_flag |= WSLEEP;
6770Sstevel@tonic-gate 
6780Sstevel@tonic-gate 				/* ensure strwsrv gets enabled */
6790Sstevel@tonic-gate 				qp->q_next->q_flag |= QWANTW;
6800Sstevel@tonic-gate 				mutex_exit(QLOCK(qp->q_next));
6810Sstevel@tonic-gate 				/* get out if we timed out or recv'd a signal */
6820Sstevel@tonic-gate 				if (str_cv_wait(&qp->q_wait, &stp->sd_lock,
6830Sstevel@tonic-gate 				    stp->sd_closetime, 0) <= 0) {
6840Sstevel@tonic-gate 					break;
6850Sstevel@tonic-gate 				}
6860Sstevel@tonic-gate 			}
6870Sstevel@tonic-gate 			stp->sd_flag &= ~WSLEEP;
6880Sstevel@tonic-gate 		}
6890Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
6900Sstevel@tonic-gate 
6910Sstevel@tonic-gate 		rmq = qp->q_next;
6920Sstevel@tonic-gate 		if (rmq->q_flag & QISDRV) {
6930Sstevel@tonic-gate 			ASSERT(!_SAMESTR(rmq));
6940Sstevel@tonic-gate 			wait_sq_svc(_RD(qp)->q_syncq);
6950Sstevel@tonic-gate 		}
6960Sstevel@tonic-gate 
6970Sstevel@tonic-gate 		qdetach(_RD(rmq), 1, flag, crp, B_FALSE);
6980Sstevel@tonic-gate 	}
6990Sstevel@tonic-gate 
7000Sstevel@tonic-gate 	/* Prevent qenable from re-enabling the stream head queue */
7010Sstevel@tonic-gate 	disable_svc(_RD(qp));
7020Sstevel@tonic-gate 
7030Sstevel@tonic-gate 	/*
7040Sstevel@tonic-gate 	 * Wait until service procedure of each queue is
7050Sstevel@tonic-gate 	 * run, if QINSERVICE is set.
7060Sstevel@tonic-gate 	 */
7070Sstevel@tonic-gate 	wait_svc(_RD(qp));
7080Sstevel@tonic-gate 
7090Sstevel@tonic-gate 	/*
7100Sstevel@tonic-gate 	 * Now, flush both queues.
7110Sstevel@tonic-gate 	 */
7120Sstevel@tonic-gate 	flushq(_RD(qp), FLUSHALL);
7130Sstevel@tonic-gate 	flushq(qp, FLUSHALL);
7140Sstevel@tonic-gate 
7150Sstevel@tonic-gate 	/*
7160Sstevel@tonic-gate 	 * If the write queue of the stream head is pointing to a
7170Sstevel@tonic-gate 	 * read queue, we have a twisted stream.  If the read queue
7180Sstevel@tonic-gate 	 * is alive, convert the stream head queues into a dead end.
7190Sstevel@tonic-gate 	 * If the read queue is dead, free the dead pair.
7200Sstevel@tonic-gate 	 */
7210Sstevel@tonic-gate 	if (qp->q_next && !_SAMESTR(qp)) {
7220Sstevel@tonic-gate 		if (qp->q_next->q_qinfo == &deadrend) {	/* half-closed pipe */
7230Sstevel@tonic-gate 			flushq(qp->q_next, FLUSHALL); /* ensure no message */
7240Sstevel@tonic-gate 			shfree(qp->q_next->q_stream);
7250Sstevel@tonic-gate 			freeq(qp->q_next);
7260Sstevel@tonic-gate 			freeq(_RD(qp));
7270Sstevel@tonic-gate 		} else if (qp->q_next == _RD(qp)) {	/* fifo */
7280Sstevel@tonic-gate 			freeq(_RD(qp));
7290Sstevel@tonic-gate 		} else {				/* pipe */
7300Sstevel@tonic-gate 			freestp = 0;
7310Sstevel@tonic-gate 			/*
7320Sstevel@tonic-gate 			 * The q_info pointers are never accessed when
7330Sstevel@tonic-gate 			 * SQLOCK is held.
7340Sstevel@tonic-gate 			 */
7350Sstevel@tonic-gate 			ASSERT(qp->q_syncq == _RD(qp)->q_syncq);
7360Sstevel@tonic-gate 			mutex_enter(SQLOCK(qp->q_syncq));
7370Sstevel@tonic-gate 			qp->q_qinfo = &deadwend;
7380Sstevel@tonic-gate 			_RD(qp)->q_qinfo = &deadrend;
7390Sstevel@tonic-gate 			mutex_exit(SQLOCK(qp->q_syncq));
7400Sstevel@tonic-gate 		}
7410Sstevel@tonic-gate 	} else {
7420Sstevel@tonic-gate 		freeq(_RD(qp)); /* free stream head queue pair */
7430Sstevel@tonic-gate 	}
7440Sstevel@tonic-gate 
7450Sstevel@tonic-gate 	mutex_enter(&vp->v_lock);
7460Sstevel@tonic-gate 	if (stp->sd_iocblk) {
7470Sstevel@tonic-gate 		if (stp->sd_iocblk != (mblk_t *)-1) {
7480Sstevel@tonic-gate 			freemsg(stp->sd_iocblk);
7490Sstevel@tonic-gate 		}
7500Sstevel@tonic-gate 		stp->sd_iocblk = NULL;
7510Sstevel@tonic-gate 	}
7520Sstevel@tonic-gate 	stp->sd_vnode = NULL;
7530Sstevel@tonic-gate 	vp->v_stream = NULL;
7540Sstevel@tonic-gate 	mutex_exit(&vp->v_lock);
7550Sstevel@tonic-gate 	mutex_enter(&stp->sd_lock);
7560Sstevel@tonic-gate 	stp->sd_flag &= ~STRCLOSE;
7570Sstevel@tonic-gate 	cv_broadcast(&stp->sd_monitor);
7580Sstevel@tonic-gate 	mutex_exit(&stp->sd_lock);
7590Sstevel@tonic-gate 
7600Sstevel@tonic-gate 	if (freestp)
7610Sstevel@tonic-gate 		shfree(stp);
7620Sstevel@tonic-gate 	return (0);
7630Sstevel@tonic-gate }
7640Sstevel@tonic-gate 
7650Sstevel@tonic-gate static int
7660Sstevel@tonic-gate strsink(queue_t *q, mblk_t *bp)
7670Sstevel@tonic-gate {
7680Sstevel@tonic-gate 	struct copyresp *resp;
7690Sstevel@tonic-gate 
7700Sstevel@tonic-gate 	switch (bp->b_datap->db_type) {
7710Sstevel@tonic-gate 	case M_FLUSH:
7720Sstevel@tonic-gate 		if ((*bp->b_rptr & FLUSHW) && !(bp->b_flag & MSGNOLOOP)) {
7730Sstevel@tonic-gate 			*bp->b_rptr &= ~FLUSHR;
7740Sstevel@tonic-gate 			bp->b_flag |= MSGNOLOOP;
7750Sstevel@tonic-gate 			/*
7760Sstevel@tonic-gate 			 * Protect against the driver passing up
7770Sstevel@tonic-gate 			 * messages after it has done a qprocsoff.
7780Sstevel@tonic-gate 			 */
7790Sstevel@tonic-gate 			if (_OTHERQ(q)->q_next == NULL)
7800Sstevel@tonic-gate 				freemsg(bp);
7810Sstevel@tonic-gate 			else
7820Sstevel@tonic-gate 				qreply(q, bp);
7830Sstevel@tonic-gate 		} else {
7840Sstevel@tonic-gate 			freemsg(bp);
7850Sstevel@tonic-gate 		}
7860Sstevel@tonic-gate 		break;
7870Sstevel@tonic-gate 
7880Sstevel@tonic-gate 	case M_COPYIN:
7890Sstevel@tonic-gate 	case M_COPYOUT:
7900Sstevel@tonic-gate 		if (bp->b_cont) {
7910Sstevel@tonic-gate 			freemsg(bp->b_cont);
7920Sstevel@tonic-gate 			bp->b_cont = NULL;
7930Sstevel@tonic-gate 		}
7940Sstevel@tonic-gate 		bp->b_datap->db_type = M_IOCDATA;
7950Sstevel@tonic-gate 		bp->b_wptr = bp->b_rptr + sizeof (struct copyresp);
7960Sstevel@tonic-gate 		resp = (struct copyresp *)bp->b_rptr;
7970Sstevel@tonic-gate 		resp->cp_rval = (caddr_t)1;	/* failure */
7980Sstevel@tonic-gate 		/*
7990Sstevel@tonic-gate 		 * Protect against the driver passing up
8000Sstevel@tonic-gate 		 * messages after it has done a qprocsoff.
8010Sstevel@tonic-gate 		 */
8020Sstevel@tonic-gate 		if (_OTHERQ(q)->q_next == NULL)
8030Sstevel@tonic-gate 			freemsg(bp);
8040Sstevel@tonic-gate 		else
8050Sstevel@tonic-gate 			qreply(q, bp);
8060Sstevel@tonic-gate 		break;
8070Sstevel@tonic-gate 
8080Sstevel@tonic-gate 	case M_IOCTL:
8090Sstevel@tonic-gate 		if (bp->b_cont) {
8100Sstevel@tonic-gate 			freemsg(bp->b_cont);
8110Sstevel@tonic-gate 			bp->b_cont = NULL;
8120Sstevel@tonic-gate 		}
8130Sstevel@tonic-gate 		bp->b_datap->db_type = M_IOCNAK;
8140Sstevel@tonic-gate 		/*
8150Sstevel@tonic-gate 		 * Protect against the driver passing up
8160Sstevel@tonic-gate 		 * messages after it has done a qprocsoff.
8170Sstevel@tonic-gate 		 */
8180Sstevel@tonic-gate 		if (_OTHERQ(q)->q_next == NULL)
8190Sstevel@tonic-gate 			freemsg(bp);
8200Sstevel@tonic-gate 		else
8210Sstevel@tonic-gate 			qreply(q, bp);
8220Sstevel@tonic-gate 		break;
8230Sstevel@tonic-gate 
8240Sstevel@tonic-gate 	default:
8250Sstevel@tonic-gate 		freemsg(bp);
8260Sstevel@tonic-gate 		break;
8270Sstevel@tonic-gate 	}
8280Sstevel@tonic-gate 
8290Sstevel@tonic-gate 	return (0);
8300Sstevel@tonic-gate }
8310Sstevel@tonic-gate 
8320Sstevel@tonic-gate /*
8330Sstevel@tonic-gate  * Clean up after a process when it closes a stream.  This is called
8340Sstevel@tonic-gate  * from closef for all closes, whereas strclose is called only for the
8350Sstevel@tonic-gate  * last close on a stream.  The siglist is scanned for entries for the
8360Sstevel@tonic-gate  * current process, and these are removed.
8370Sstevel@tonic-gate  */
8380Sstevel@tonic-gate void
8390Sstevel@tonic-gate strclean(struct vnode *vp)
8400Sstevel@tonic-gate {
8410Sstevel@tonic-gate 	strsig_t *ssp, *pssp, *tssp;
8420Sstevel@tonic-gate 	stdata_t *stp;
8430Sstevel@tonic-gate 	int update = 0;
8440Sstevel@tonic-gate 
8450Sstevel@tonic-gate 	TRACE_1(TR_FAC_STREAMS_FR,
8460Sstevel@tonic-gate 		TR_STRCLEAN, "strclean:%p", vp);
8470Sstevel@tonic-gate 	stp = vp->v_stream;
8480Sstevel@tonic-gate 	pssp = NULL;
8490Sstevel@tonic-gate 	mutex_enter(&stp->sd_lock);
8500Sstevel@tonic-gate 	ssp = stp->sd_siglist;
8510Sstevel@tonic-gate 	while (ssp) {
8520Sstevel@tonic-gate 		if (ssp->ss_pidp == curproc->p_pidp) {
8530Sstevel@tonic-gate 			tssp = ssp->ss_next;
8540Sstevel@tonic-gate 			if (pssp)
8550Sstevel@tonic-gate 				pssp->ss_next = tssp;
8560Sstevel@tonic-gate 			else
8570Sstevel@tonic-gate 				stp->sd_siglist = tssp;
8580Sstevel@tonic-gate 			mutex_enter(&pidlock);
8590Sstevel@tonic-gate 			PID_RELE(ssp->ss_pidp);
8600Sstevel@tonic-gate 			mutex_exit(&pidlock);
8610Sstevel@tonic-gate 			kmem_free(ssp, sizeof (strsig_t));
8620Sstevel@tonic-gate 			update = 1;
8630Sstevel@tonic-gate 			ssp = tssp;
8640Sstevel@tonic-gate 		} else {
8650Sstevel@tonic-gate 			pssp = ssp;
8660Sstevel@tonic-gate 			ssp = ssp->ss_next;
8670Sstevel@tonic-gate 		}
8680Sstevel@tonic-gate 	}
8690Sstevel@tonic-gate 	if (update) {
8700Sstevel@tonic-gate 		stp->sd_sigflags = 0;
8710Sstevel@tonic-gate 		for (ssp = stp->sd_siglist; ssp; ssp = ssp->ss_next)
8720Sstevel@tonic-gate 			stp->sd_sigflags |= ssp->ss_events;
8730Sstevel@tonic-gate 	}
8740Sstevel@tonic-gate 	mutex_exit(&stp->sd_lock);
8750Sstevel@tonic-gate }
8760Sstevel@tonic-gate 
8770Sstevel@tonic-gate /*
8780Sstevel@tonic-gate  * Used on the last close to remove any remaining items on the siglist.
8790Sstevel@tonic-gate  * These could be present on the siglist due to I_ESETSIG calls that
8800Sstevel@tonic-gate  * use process groups or processed that do not have an open file descriptor
8810Sstevel@tonic-gate  * for this stream (Such entries would not be removed by strclean).
8820Sstevel@tonic-gate  */
8830Sstevel@tonic-gate static void
8840Sstevel@tonic-gate strcleanall(struct vnode *vp)
8850Sstevel@tonic-gate {
8860Sstevel@tonic-gate 	strsig_t *ssp, *nssp;
8870Sstevel@tonic-gate 	stdata_t *stp;
8880Sstevel@tonic-gate 
8890Sstevel@tonic-gate 	stp = vp->v_stream;
8900Sstevel@tonic-gate 	mutex_enter(&stp->sd_lock);
8910Sstevel@tonic-gate 	ssp = stp->sd_siglist;
8920Sstevel@tonic-gate 	stp->sd_siglist = NULL;
8930Sstevel@tonic-gate 	while (ssp) {
8940Sstevel@tonic-gate 		nssp = ssp->ss_next;
8950Sstevel@tonic-gate 		mutex_enter(&pidlock);
8960Sstevel@tonic-gate 		PID_RELE(ssp->ss_pidp);
8970Sstevel@tonic-gate 		mutex_exit(&pidlock);
8980Sstevel@tonic-gate 		kmem_free(ssp, sizeof (strsig_t));
8990Sstevel@tonic-gate 		ssp = nssp;
9000Sstevel@tonic-gate 	}
9010Sstevel@tonic-gate 	stp->sd_sigflags = 0;
9020Sstevel@tonic-gate 	mutex_exit(&stp->sd_lock);
9030Sstevel@tonic-gate }
9040Sstevel@tonic-gate 
9050Sstevel@tonic-gate /*
9060Sstevel@tonic-gate  * Retrieve the next message from the logical stream head read queue
9070Sstevel@tonic-gate  * using either rwnext (if sync stream) or getq_noenab.
9080Sstevel@tonic-gate  * It is the callers responsibility to call qbackenable after
9090Sstevel@tonic-gate  * it is finished with the message. The caller should not call
9100Sstevel@tonic-gate  * qbackenable until after any putback calls to avoid spurious backenabling.
9110Sstevel@tonic-gate  */
9120Sstevel@tonic-gate mblk_t *
9130Sstevel@tonic-gate strget(struct stdata *stp, queue_t *q, struct uio *uiop, int first,
9140Sstevel@tonic-gate     int *errorp)
9150Sstevel@tonic-gate {
9160Sstevel@tonic-gate 	mblk_t *bp;
9170Sstevel@tonic-gate 	int error;
9180Sstevel@tonic-gate 
9190Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&stp->sd_lock));
9200Sstevel@tonic-gate 	/* Holding sd_lock prevents the read queue from changing  */
9210Sstevel@tonic-gate 
9220Sstevel@tonic-gate 	if (uiop != NULL && stp->sd_struiordq != NULL &&
9230Sstevel@tonic-gate 	    q->q_first == NULL &&
9240Sstevel@tonic-gate 	    (!first || (stp->sd_wakeq & RSLEEP))) {
9250Sstevel@tonic-gate 		/*
9260Sstevel@tonic-gate 		 * Stream supports rwnext() for the read side.
9270Sstevel@tonic-gate 		 * If this is the first time we're called by e.g. strread
9280Sstevel@tonic-gate 		 * only do the downcall if there is a deferred wakeup
9290Sstevel@tonic-gate 		 * (registered in sd_wakeq).
9300Sstevel@tonic-gate 		 */
9310Sstevel@tonic-gate 		struiod_t uiod;
9320Sstevel@tonic-gate 
9330Sstevel@tonic-gate 		if (first)
9340Sstevel@tonic-gate 			stp->sd_wakeq &= ~RSLEEP;
9350Sstevel@tonic-gate 
9360Sstevel@tonic-gate 		(void) uiodup(uiop, &uiod.d_uio, uiod.d_iov,
9370Sstevel@tonic-gate 			sizeof (uiod.d_iov) / sizeof (*uiod.d_iov));
9380Sstevel@tonic-gate 		uiod.d_mp = 0;
9390Sstevel@tonic-gate 		/*
9400Sstevel@tonic-gate 		 * Mark that a thread is in rwnext on the read side
9410Sstevel@tonic-gate 		 * to prevent strrput from nacking ioctls immediately.
9420Sstevel@tonic-gate 		 * When the last concurrent rwnext returns
9430Sstevel@tonic-gate 		 * the ioctls are nack'ed.
9440Sstevel@tonic-gate 		 */
9450Sstevel@tonic-gate 		ASSERT(MUTEX_HELD(&stp->sd_lock));
9460Sstevel@tonic-gate 		stp->sd_struiodnak++;
9470Sstevel@tonic-gate 		/*
9480Sstevel@tonic-gate 		 * Note: rwnext will drop sd_lock.
9490Sstevel@tonic-gate 		 */
9500Sstevel@tonic-gate 		error = rwnext(q, &uiod);
9510Sstevel@tonic-gate 		ASSERT(MUTEX_NOT_HELD(&stp->sd_lock));
9520Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
9530Sstevel@tonic-gate 		stp->sd_struiodnak--;
9540Sstevel@tonic-gate 		while (stp->sd_struiodnak == 0 &&
9550Sstevel@tonic-gate 		    ((bp = stp->sd_struionak) != NULL)) {
9560Sstevel@tonic-gate 			stp->sd_struionak = bp->b_next;
9570Sstevel@tonic-gate 			bp->b_next = NULL;
9580Sstevel@tonic-gate 			bp->b_datap->db_type = M_IOCNAK;
9590Sstevel@tonic-gate 			/*
9600Sstevel@tonic-gate 			 * Protect against the driver passing up
9610Sstevel@tonic-gate 			 * messages after it has done a qprocsoff.
9620Sstevel@tonic-gate 			 */
9630Sstevel@tonic-gate 			if (_OTHERQ(q)->q_next == NULL)
9640Sstevel@tonic-gate 				freemsg(bp);
9650Sstevel@tonic-gate 			else {
9660Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
9670Sstevel@tonic-gate 				qreply(q, bp);
9680Sstevel@tonic-gate 				mutex_enter(&stp->sd_lock);
9690Sstevel@tonic-gate 			}
9700Sstevel@tonic-gate 		}
9710Sstevel@tonic-gate 		ASSERT(MUTEX_HELD(&stp->sd_lock));
9720Sstevel@tonic-gate 		if (error == 0 || error == EWOULDBLOCK) {
9730Sstevel@tonic-gate 			if ((bp = uiod.d_mp) != NULL) {
9740Sstevel@tonic-gate 				*errorp = 0;
9750Sstevel@tonic-gate 				ASSERT(MUTEX_HELD(&stp->sd_lock));
9760Sstevel@tonic-gate 				return (bp);
9770Sstevel@tonic-gate 			}
9780Sstevel@tonic-gate 			error = 0;
9790Sstevel@tonic-gate 		} else if (error == EINVAL) {
9800Sstevel@tonic-gate 			/*
9810Sstevel@tonic-gate 			 * The stream plumbing must have
9820Sstevel@tonic-gate 			 * changed while we were away, so
9830Sstevel@tonic-gate 			 * just turn off rwnext()s.
9840Sstevel@tonic-gate 			 */
9850Sstevel@tonic-gate 			error = 0;
9860Sstevel@tonic-gate 		} else if (error == EBUSY) {
9870Sstevel@tonic-gate 			/*
9880Sstevel@tonic-gate 			 * The module might have data in transit using putnext
9890Sstevel@tonic-gate 			 * Fall back on waiting + getq.
9900Sstevel@tonic-gate 			 */
9910Sstevel@tonic-gate 			error = 0;
9920Sstevel@tonic-gate 		} else {
9930Sstevel@tonic-gate 			*errorp = error;
9940Sstevel@tonic-gate 			ASSERT(MUTEX_HELD(&stp->sd_lock));
9950Sstevel@tonic-gate 			return (NULL);
9960Sstevel@tonic-gate 		}
9970Sstevel@tonic-gate 		/*
9980Sstevel@tonic-gate 		 * Try a getq in case a rwnext() generated mblk
9990Sstevel@tonic-gate 		 * has bubbled up via strrput().
10000Sstevel@tonic-gate 		 */
10010Sstevel@tonic-gate 	}
10020Sstevel@tonic-gate 	*errorp = 0;
10030Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&stp->sd_lock));
10040Sstevel@tonic-gate 	return (getq_noenab(q));
10050Sstevel@tonic-gate }
10060Sstevel@tonic-gate 
10070Sstevel@tonic-gate /*
10080Sstevel@tonic-gate  * Copy out the message pointed to by `bp' into the uio pointed to by `uiop'.
10090Sstevel@tonic-gate  * If the message does not fit in the uio the remainder of it is returned;
10100Sstevel@tonic-gate  * otherwise NULL is returned.  Any embedded zero-length mblk_t's are
10110Sstevel@tonic-gate  * consumed, even if uio_resid reaches zero.  On error, `*errorp' is set to
10120Sstevel@tonic-gate  * the error code, the message is consumed, and NULL is returned.
10130Sstevel@tonic-gate  */
10140Sstevel@tonic-gate static mblk_t *
10150Sstevel@tonic-gate struiocopyout(mblk_t *bp, struct uio *uiop, int *errorp)
10160Sstevel@tonic-gate {
10170Sstevel@tonic-gate 	int error;
10180Sstevel@tonic-gate 	ptrdiff_t n;
10190Sstevel@tonic-gate 	mblk_t *nbp;
10200Sstevel@tonic-gate 
10210Sstevel@tonic-gate 	ASSERT(bp->b_wptr >= bp->b_rptr);
10220Sstevel@tonic-gate 
10230Sstevel@tonic-gate 	do {
10240Sstevel@tonic-gate 		if ((n = MIN(uiop->uio_resid, MBLKL(bp))) != 0) {
10250Sstevel@tonic-gate 			ASSERT(n > 0);
10260Sstevel@tonic-gate 
10270Sstevel@tonic-gate 			error = uiomove(bp->b_rptr, n, UIO_READ, uiop);
10280Sstevel@tonic-gate 			if (error != 0) {
10290Sstevel@tonic-gate 				freemsg(bp);
10300Sstevel@tonic-gate 				*errorp = error;
10310Sstevel@tonic-gate 				return (NULL);
10320Sstevel@tonic-gate 			}
10330Sstevel@tonic-gate 		}
10340Sstevel@tonic-gate 
10350Sstevel@tonic-gate 		bp->b_rptr += n;
10360Sstevel@tonic-gate 		while (bp != NULL && (bp->b_rptr >= bp->b_wptr)) {
10370Sstevel@tonic-gate 			nbp = bp;
10380Sstevel@tonic-gate 			bp = bp->b_cont;
10390Sstevel@tonic-gate 			freeb(nbp);
10400Sstevel@tonic-gate 		}
10410Sstevel@tonic-gate 	} while (bp != NULL && uiop->uio_resid > 0);
10420Sstevel@tonic-gate 
10430Sstevel@tonic-gate 	*errorp = 0;
10440Sstevel@tonic-gate 	return (bp);
10450Sstevel@tonic-gate }
10460Sstevel@tonic-gate 
10470Sstevel@tonic-gate /*
10480Sstevel@tonic-gate  * Read a stream according to the mode flags in sd_flag:
10490Sstevel@tonic-gate  *
10500Sstevel@tonic-gate  * (default mode)		- Byte stream, msg boundaries are ignored
10510Sstevel@tonic-gate  * RD_MSGDIS (msg discard)	- Read on msg boundaries and throw away
10520Sstevel@tonic-gate  *				any data remaining in msg
10530Sstevel@tonic-gate  * RD_MSGNODIS (msg non-discard) - Read on msg boundaries and put back
10540Sstevel@tonic-gate  *				any remaining data on head of read queue
10550Sstevel@tonic-gate  *
10560Sstevel@tonic-gate  * Consume readable messages on the front of the queue until
10570Sstevel@tonic-gate  * ttolwp(curthread)->lwp_count
10580Sstevel@tonic-gate  * is satisfied, the readable messages are exhausted, or a message
10590Sstevel@tonic-gate  * boundary is reached in a message mode.  If no data was read and
10600Sstevel@tonic-gate  * the stream was not opened with the NDELAY flag, block until data arrives.
10610Sstevel@tonic-gate  * Otherwise return the data read and update the count.
10620Sstevel@tonic-gate  *
10630Sstevel@tonic-gate  * In default mode a 0 length message signifies end-of-file and terminates
10640Sstevel@tonic-gate  * a read in progress.  The 0 length message is removed from the queue
10650Sstevel@tonic-gate  * only if it is the only message read (no data is read).
10660Sstevel@tonic-gate  *
10670Sstevel@tonic-gate  * An attempt to read an M_PROTO or M_PCPROTO message results in an
10680Sstevel@tonic-gate  * EBADMSG error return, unless either RD_PROTDAT or RD_PROTDIS are set.
10690Sstevel@tonic-gate  * If RD_PROTDAT is set, M_PROTO and M_PCPROTO messages are read as data.
10700Sstevel@tonic-gate  * If RD_PROTDIS is set, the M_PROTO and M_PCPROTO parts of the message
10710Sstevel@tonic-gate  * are unlinked from and M_DATA blocks in the message, the protos are
10720Sstevel@tonic-gate  * thrown away, and the data is read.
10730Sstevel@tonic-gate  */
10740Sstevel@tonic-gate /* ARGSUSED */
10750Sstevel@tonic-gate int
10760Sstevel@tonic-gate strread(struct vnode *vp, struct uio *uiop, cred_t *crp)
10770Sstevel@tonic-gate {
10780Sstevel@tonic-gate 	struct stdata *stp;
10790Sstevel@tonic-gate 	mblk_t *bp, *nbp;
10800Sstevel@tonic-gate 	queue_t *q;
10810Sstevel@tonic-gate 	int error = 0;
10820Sstevel@tonic-gate 	uint_t old_sd_flag;
10830Sstevel@tonic-gate 	int first;
10840Sstevel@tonic-gate 	char rflg;
10850Sstevel@tonic-gate 	uint_t mark;		/* Contains MSG*MARK and _LASTMARK */
10860Sstevel@tonic-gate #define	_LASTMARK	0x8000	/* Distinct from MSG*MARK */
10870Sstevel@tonic-gate 	short delim;
10880Sstevel@tonic-gate 	unsigned char pri = 0;
10890Sstevel@tonic-gate 	char waitflag;
10900Sstevel@tonic-gate 	unsigned char type;
10910Sstevel@tonic-gate 
10920Sstevel@tonic-gate 	TRACE_1(TR_FAC_STREAMS_FR,
10930Sstevel@tonic-gate 		TR_STRREAD_ENTER, "strread:%p", vp);
10940Sstevel@tonic-gate 	ASSERT(vp->v_stream);
10950Sstevel@tonic-gate 	stp = vp->v_stream;
10960Sstevel@tonic-gate 
10970Sstevel@tonic-gate 	if (stp->sd_sidp != NULL && stp->sd_vnode->v_type != VFIFO)
10980Sstevel@tonic-gate 		if (error = straccess(stp, JCREAD))
10990Sstevel@tonic-gate 			return (error);
11000Sstevel@tonic-gate 
11010Sstevel@tonic-gate 	mutex_enter(&stp->sd_lock);
11020Sstevel@tonic-gate 	if (stp->sd_flag & (STRDERR|STPLEX)) {
11030Sstevel@tonic-gate 		error = strgeterr(stp, STRDERR|STPLEX, 0);
11040Sstevel@tonic-gate 		if (error != 0) {
11050Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
11060Sstevel@tonic-gate 			return (error);
11070Sstevel@tonic-gate 		}
11080Sstevel@tonic-gate 	}
11090Sstevel@tonic-gate 
11100Sstevel@tonic-gate 	/*
11110Sstevel@tonic-gate 	 * Loop terminates when uiop->uio_resid == 0.
11120Sstevel@tonic-gate 	 */
11130Sstevel@tonic-gate 	rflg = 0;
11140Sstevel@tonic-gate 	waitflag = READWAIT;
11150Sstevel@tonic-gate 	q = _RD(stp->sd_wrq);
11160Sstevel@tonic-gate 	for (;;) {
11170Sstevel@tonic-gate 		ASSERT(MUTEX_HELD(&stp->sd_lock));
11180Sstevel@tonic-gate 		old_sd_flag = stp->sd_flag;
11190Sstevel@tonic-gate 		mark = 0;
11200Sstevel@tonic-gate 		delim = 0;
11210Sstevel@tonic-gate 		first = 1;
11220Sstevel@tonic-gate 		while ((bp = strget(stp, q, uiop, first, &error)) == NULL) {
11230Sstevel@tonic-gate 			int done = 0;
11240Sstevel@tonic-gate 
11250Sstevel@tonic-gate 			ASSERT(MUTEX_HELD(&stp->sd_lock));
11260Sstevel@tonic-gate 
11270Sstevel@tonic-gate 			if (error != 0)
11280Sstevel@tonic-gate 				goto oops;
11290Sstevel@tonic-gate 
11300Sstevel@tonic-gate 			if (stp->sd_flag & (STRHUP|STREOF)) {
11310Sstevel@tonic-gate 				goto oops;
11320Sstevel@tonic-gate 			}
11330Sstevel@tonic-gate 			if (rflg && !(stp->sd_flag & STRDELIM)) {
11340Sstevel@tonic-gate 				goto oops;
11350Sstevel@tonic-gate 			}
11360Sstevel@tonic-gate 			/*
11370Sstevel@tonic-gate 			 * If a read(fd,buf,0) has been done, there is no
11380Sstevel@tonic-gate 			 * need to sleep. We always have zero bytes to
11390Sstevel@tonic-gate 			 * return.
11400Sstevel@tonic-gate 			 */
11410Sstevel@tonic-gate 			if (uiop->uio_resid == 0) {
11420Sstevel@tonic-gate 				goto oops;
11430Sstevel@tonic-gate 			}
11440Sstevel@tonic-gate 
11450Sstevel@tonic-gate 			qbackenable(q, 0);
11460Sstevel@tonic-gate 
11470Sstevel@tonic-gate 			TRACE_3(TR_FAC_STREAMS_FR, TR_STRREAD_WAIT,
11480Sstevel@tonic-gate 				"strread calls strwaitq:%p, %p, %p",
11490Sstevel@tonic-gate 				vp, uiop, crp);
11500Sstevel@tonic-gate 			if ((error = strwaitq(stp, waitflag, uiop->uio_resid,
11510Sstevel@tonic-gate 			    uiop->uio_fmode, -1, &done)) != 0 || done) {
11520Sstevel@tonic-gate 				TRACE_3(TR_FAC_STREAMS_FR, TR_STRREAD_DONE,
11530Sstevel@tonic-gate 					"strread error or done:%p, %p, %p",
11540Sstevel@tonic-gate 					vp, uiop, crp);
11550Sstevel@tonic-gate 				if ((uiop->uio_fmode & FNDELAY) &&
11560Sstevel@tonic-gate 				    (stp->sd_flag & OLDNDELAY) &&
11570Sstevel@tonic-gate 				    (error == EAGAIN))
11580Sstevel@tonic-gate 					error = 0;
11590Sstevel@tonic-gate 				goto oops;
11600Sstevel@tonic-gate 			}
11610Sstevel@tonic-gate 			TRACE_3(TR_FAC_STREAMS_FR, TR_STRREAD_AWAKE,
11620Sstevel@tonic-gate 				"strread awakes:%p, %p, %p", vp, uiop, crp);
11630Sstevel@tonic-gate 			if (stp->sd_sidp != NULL &&
11640Sstevel@tonic-gate 			    stp->sd_vnode->v_type != VFIFO) {
11650Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
11660Sstevel@tonic-gate 				if (error = straccess(stp, JCREAD))
11670Sstevel@tonic-gate 					goto oops1;
11680Sstevel@tonic-gate 				mutex_enter(&stp->sd_lock);
11690Sstevel@tonic-gate 			}
11700Sstevel@tonic-gate 			first = 0;
11710Sstevel@tonic-gate 		}
11720Sstevel@tonic-gate 		ASSERT(MUTEX_HELD(&stp->sd_lock));
11730Sstevel@tonic-gate 		ASSERT(bp);
11740Sstevel@tonic-gate 		pri = bp->b_band;
11750Sstevel@tonic-gate 		/*
11760Sstevel@tonic-gate 		 * Extract any mark information. If the message is not
11770Sstevel@tonic-gate 		 * completely consumed this information will be put in the mblk
11780Sstevel@tonic-gate 		 * that is putback.
11790Sstevel@tonic-gate 		 * If MSGMARKNEXT is set and the message is completely consumed
11800Sstevel@tonic-gate 		 * the STRATMARK flag will be set below. Likewise, if
11810Sstevel@tonic-gate 		 * MSGNOTMARKNEXT is set and the message is
11820Sstevel@tonic-gate 		 * completely consumed STRNOTATMARK will be set.
11830Sstevel@tonic-gate 		 *
11840Sstevel@tonic-gate 		 * For some unknown reason strread only breaks the read at the
11850Sstevel@tonic-gate 		 * last mark.
11860Sstevel@tonic-gate 		 */
11870Sstevel@tonic-gate 		mark = bp->b_flag & (MSGMARK | MSGMARKNEXT | MSGNOTMARKNEXT);
11880Sstevel@tonic-gate 		ASSERT((mark & (MSGMARKNEXT|MSGNOTMARKNEXT)) !=
11890Sstevel@tonic-gate 			(MSGMARKNEXT|MSGNOTMARKNEXT));
11900Sstevel@tonic-gate 		if (mark != 0 && bp == stp->sd_mark) {
11910Sstevel@tonic-gate 			if (rflg) {
11920Sstevel@tonic-gate 				putback(stp, q, bp, pri);
11930Sstevel@tonic-gate 				goto oops;
11940Sstevel@tonic-gate 			}
11950Sstevel@tonic-gate 			mark |= _LASTMARK;
11960Sstevel@tonic-gate 			stp->sd_mark = NULL;
11970Sstevel@tonic-gate 		}
11980Sstevel@tonic-gate 		if ((stp->sd_flag & STRDELIM) && (bp->b_flag & MSGDELIM))
11990Sstevel@tonic-gate 			delim = 1;
12000Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
12010Sstevel@tonic-gate 
12020Sstevel@tonic-gate 		if (STREAM_NEEDSERVICE(stp))
12030Sstevel@tonic-gate 			stream_runservice(stp);
12040Sstevel@tonic-gate 
12050Sstevel@tonic-gate 		type = bp->b_datap->db_type;
12060Sstevel@tonic-gate 
12070Sstevel@tonic-gate 		switch (type) {
12080Sstevel@tonic-gate 
12090Sstevel@tonic-gate 		case M_DATA:
12100Sstevel@tonic-gate ismdata:
12110Sstevel@tonic-gate 			if (msgnodata(bp)) {
12120Sstevel@tonic-gate 				if (mark || delim) {
12130Sstevel@tonic-gate 					freemsg(bp);
12140Sstevel@tonic-gate 				} else if (rflg) {
12150Sstevel@tonic-gate 
12160Sstevel@tonic-gate 					/*
12170Sstevel@tonic-gate 					 * If already read data put zero
12180Sstevel@tonic-gate 					 * length message back on queue else
12190Sstevel@tonic-gate 					 * free msg and return 0.
12200Sstevel@tonic-gate 					 */
12210Sstevel@tonic-gate 					bp->b_band = pri;
12220Sstevel@tonic-gate 					mutex_enter(&stp->sd_lock);
12230Sstevel@tonic-gate 					putback(stp, q, bp, pri);
12240Sstevel@tonic-gate 					mutex_exit(&stp->sd_lock);
12250Sstevel@tonic-gate 				} else {
12260Sstevel@tonic-gate 					freemsg(bp);
12270Sstevel@tonic-gate 				}
12280Sstevel@tonic-gate 				error =  0;
12290Sstevel@tonic-gate 				goto oops1;
12300Sstevel@tonic-gate 			}
12310Sstevel@tonic-gate 
12320Sstevel@tonic-gate 			rflg = 1;
12330Sstevel@tonic-gate 			waitflag |= NOINTR;
12340Sstevel@tonic-gate 			bp = struiocopyout(bp, uiop, &error);
12350Sstevel@tonic-gate 			if (error != 0)
12360Sstevel@tonic-gate 				goto oops1;
12370Sstevel@tonic-gate 
12380Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
12390Sstevel@tonic-gate 			if (bp) {
12400Sstevel@tonic-gate 				/*
12410Sstevel@tonic-gate 				 * Have remaining data in message.
12420Sstevel@tonic-gate 				 * Free msg if in discard mode.
12430Sstevel@tonic-gate 				 */
12440Sstevel@tonic-gate 				if (stp->sd_read_opt & RD_MSGDIS) {
12450Sstevel@tonic-gate 					freemsg(bp);
12460Sstevel@tonic-gate 				} else {
12470Sstevel@tonic-gate 					bp->b_band = pri;
12480Sstevel@tonic-gate 					if ((mark & _LASTMARK) &&
12490Sstevel@tonic-gate 					    (stp->sd_mark == NULL))
12500Sstevel@tonic-gate 						stp->sd_mark = bp;
12510Sstevel@tonic-gate 					bp->b_flag |= mark & ~_LASTMARK;
12520Sstevel@tonic-gate 					if (delim)
12530Sstevel@tonic-gate 						bp->b_flag |= MSGDELIM;
12540Sstevel@tonic-gate 					if (msgnodata(bp))
12550Sstevel@tonic-gate 						freemsg(bp);
12560Sstevel@tonic-gate 					else
12570Sstevel@tonic-gate 						putback(stp, q, bp, pri);
12580Sstevel@tonic-gate 				}
12590Sstevel@tonic-gate 			} else {
12600Sstevel@tonic-gate 				/*
12610Sstevel@tonic-gate 				 * Consumed the complete message.
12620Sstevel@tonic-gate 				 * Move the MSG*MARKNEXT information
12630Sstevel@tonic-gate 				 * to the stream head just in case
12640Sstevel@tonic-gate 				 * the read queue becomes empty.
12650Sstevel@tonic-gate 				 *
12660Sstevel@tonic-gate 				 * If the stream head was at the mark
12670Sstevel@tonic-gate 				 * (STRATMARK) before we dropped sd_lock above
12680Sstevel@tonic-gate 				 * and some data was consumed then we have
12690Sstevel@tonic-gate 				 * moved past the mark thus STRATMARK is
12700Sstevel@tonic-gate 				 * cleared. However, if a message arrived in
12710Sstevel@tonic-gate 				 * strrput during the copyout above causing
12720Sstevel@tonic-gate 				 * STRATMARK to be set we can not clear that
12730Sstevel@tonic-gate 				 * flag.
12740Sstevel@tonic-gate 				 */
12750Sstevel@tonic-gate 				if (mark &
12760Sstevel@tonic-gate 				    (MSGMARKNEXT|MSGNOTMARKNEXT|MSGMARK)) {
12770Sstevel@tonic-gate 					if (mark & MSGMARKNEXT) {
12780Sstevel@tonic-gate 						stp->sd_flag &= ~STRNOTATMARK;
12790Sstevel@tonic-gate 						stp->sd_flag |= STRATMARK;
12800Sstevel@tonic-gate 					} else if (mark & MSGNOTMARKNEXT) {
12810Sstevel@tonic-gate 						stp->sd_flag &= ~STRATMARK;
12820Sstevel@tonic-gate 						stp->sd_flag |= STRNOTATMARK;
12830Sstevel@tonic-gate 					} else {
12840Sstevel@tonic-gate 						stp->sd_flag &=
12850Sstevel@tonic-gate 						    ~(STRATMARK|STRNOTATMARK);
12860Sstevel@tonic-gate 					}
12870Sstevel@tonic-gate 				} else if (rflg && (old_sd_flag & STRATMARK)) {
12880Sstevel@tonic-gate 					stp->sd_flag &= ~STRATMARK;
12890Sstevel@tonic-gate 				}
12900Sstevel@tonic-gate 			}
12910Sstevel@tonic-gate 
12920Sstevel@tonic-gate 			/*
12930Sstevel@tonic-gate 			 * Check for signal messages at the front of the read
12940Sstevel@tonic-gate 			 * queue and generate the signal(s) if appropriate.
12950Sstevel@tonic-gate 			 * The only signal that can be on queue is M_SIG at
12960Sstevel@tonic-gate 			 * this point.
12970Sstevel@tonic-gate 			 */
12980Sstevel@tonic-gate 			while ((((bp = q->q_first)) != NULL) &&
12990Sstevel@tonic-gate 				(bp->b_datap->db_type == M_SIG)) {
13000Sstevel@tonic-gate 				bp = getq_noenab(q);
13010Sstevel@tonic-gate 				/*
13020Sstevel@tonic-gate 				 * sd_lock is held so the content of the
13030Sstevel@tonic-gate 				 * read queue can not change.
13040Sstevel@tonic-gate 				 */
13050Sstevel@tonic-gate 				ASSERT(bp != NULL &&
13060Sstevel@tonic-gate 					bp->b_datap->db_type == M_SIG);
13070Sstevel@tonic-gate 				strsignal_nolock(stp, *bp->b_rptr,
13080Sstevel@tonic-gate 					(int32_t)bp->b_band);
13090Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
13100Sstevel@tonic-gate 				freemsg(bp);
13110Sstevel@tonic-gate 				if (STREAM_NEEDSERVICE(stp))
13120Sstevel@tonic-gate 					stream_runservice(stp);
13130Sstevel@tonic-gate 				mutex_enter(&stp->sd_lock);
13140Sstevel@tonic-gate 			}
13150Sstevel@tonic-gate 
13160Sstevel@tonic-gate 			if ((uiop->uio_resid == 0) || (mark & _LASTMARK) ||
13170Sstevel@tonic-gate 			    delim ||
13180Sstevel@tonic-gate 			    (stp->sd_read_opt & (RD_MSGDIS|RD_MSGNODIS))) {
13190Sstevel@tonic-gate 				goto oops;
13200Sstevel@tonic-gate 			}
13210Sstevel@tonic-gate 			continue;
13220Sstevel@tonic-gate 
13230Sstevel@tonic-gate 		case M_SIG:
13240Sstevel@tonic-gate 			strsignal(stp, *bp->b_rptr, (int32_t)bp->b_band);
13250Sstevel@tonic-gate 			freemsg(bp);
13260Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
13270Sstevel@tonic-gate 			continue;
13280Sstevel@tonic-gate 
13290Sstevel@tonic-gate 		case M_PROTO:
13300Sstevel@tonic-gate 		case M_PCPROTO:
13310Sstevel@tonic-gate 			/*
13320Sstevel@tonic-gate 			 * Only data messages are readable.
13330Sstevel@tonic-gate 			 * Any others generate an error, unless
13340Sstevel@tonic-gate 			 * RD_PROTDIS or RD_PROTDAT is set.
13350Sstevel@tonic-gate 			 */
13360Sstevel@tonic-gate 			if (stp->sd_read_opt & RD_PROTDAT) {
13370Sstevel@tonic-gate 				for (nbp = bp; nbp; nbp = nbp->b_next) {
13380Sstevel@tonic-gate 				    if ((nbp->b_datap->db_type == M_PROTO) ||
13390Sstevel@tonic-gate 					(nbp->b_datap->db_type == M_PCPROTO))
13400Sstevel@tonic-gate 					nbp->b_datap->db_type = M_DATA;
13410Sstevel@tonic-gate 				    else
13420Sstevel@tonic-gate 					break;
13430Sstevel@tonic-gate 				}
13440Sstevel@tonic-gate 				/*
13450Sstevel@tonic-gate 				 * clear stream head hi pri flag based on
13460Sstevel@tonic-gate 				 * first message
13470Sstevel@tonic-gate 				 */
13480Sstevel@tonic-gate 				if (type == M_PCPROTO) {
13490Sstevel@tonic-gate 					mutex_enter(&stp->sd_lock);
13500Sstevel@tonic-gate 					stp->sd_flag &= ~STRPRI;
13510Sstevel@tonic-gate 					mutex_exit(&stp->sd_lock);
13520Sstevel@tonic-gate 				}
13530Sstevel@tonic-gate 				goto ismdata;
13540Sstevel@tonic-gate 			} else if (stp->sd_read_opt & RD_PROTDIS) {
13550Sstevel@tonic-gate 				/*
13560Sstevel@tonic-gate 				 * discard non-data messages
13570Sstevel@tonic-gate 				 */
13580Sstevel@tonic-gate 				while (bp &&
13590Sstevel@tonic-gate 				    ((bp->b_datap->db_type == M_PROTO) ||
13600Sstevel@tonic-gate 				    (bp->b_datap->db_type == M_PCPROTO))) {
13610Sstevel@tonic-gate 					nbp = unlinkb(bp);
13620Sstevel@tonic-gate 					freeb(bp);
13630Sstevel@tonic-gate 					bp = nbp;
13640Sstevel@tonic-gate 				}
13650Sstevel@tonic-gate 				/*
13660Sstevel@tonic-gate 				 * clear stream head hi pri flag based on
13670Sstevel@tonic-gate 				 * first message
13680Sstevel@tonic-gate 				 */
13690Sstevel@tonic-gate 				if (type == M_PCPROTO) {
13700Sstevel@tonic-gate 					mutex_enter(&stp->sd_lock);
13710Sstevel@tonic-gate 					stp->sd_flag &= ~STRPRI;
13720Sstevel@tonic-gate 					mutex_exit(&stp->sd_lock);
13730Sstevel@tonic-gate 				}
13740Sstevel@tonic-gate 				if (bp) {
13750Sstevel@tonic-gate 					bp->b_band = pri;
13760Sstevel@tonic-gate 					goto ismdata;
13770Sstevel@tonic-gate 				} else {
13780Sstevel@tonic-gate 					break;
13790Sstevel@tonic-gate 				}
13800Sstevel@tonic-gate 			}
13810Sstevel@tonic-gate 			/* FALLTHRU */
13820Sstevel@tonic-gate 		case M_PASSFP:
13830Sstevel@tonic-gate 			if ((bp->b_datap->db_type == M_PASSFP) &&
13840Sstevel@tonic-gate 			    (stp->sd_read_opt & RD_PROTDIS)) {
13850Sstevel@tonic-gate 				freemsg(bp);
13860Sstevel@tonic-gate 				break;
13870Sstevel@tonic-gate 			}
13880Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
13890Sstevel@tonic-gate 			putback(stp, q, bp, pri);
13900Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
13910Sstevel@tonic-gate 			if (rflg == 0)
13920Sstevel@tonic-gate 				error = EBADMSG;
13930Sstevel@tonic-gate 			goto oops1;
13940Sstevel@tonic-gate 
13950Sstevel@tonic-gate 		default:
13960Sstevel@tonic-gate 			/*
13970Sstevel@tonic-gate 			 * Garbage on stream head read queue.
13980Sstevel@tonic-gate 			 */
13990Sstevel@tonic-gate 			cmn_err(CE_WARN, "bad %x found at stream head\n",
14000Sstevel@tonic-gate 				bp->b_datap->db_type);
14010Sstevel@tonic-gate 			freemsg(bp);
14020Sstevel@tonic-gate 			goto oops1;
14030Sstevel@tonic-gate 		}
14040Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
14050Sstevel@tonic-gate 	}
14060Sstevel@tonic-gate oops:
14070Sstevel@tonic-gate 	mutex_exit(&stp->sd_lock);
14080Sstevel@tonic-gate oops1:
14090Sstevel@tonic-gate 	qbackenable(q, pri);
14100Sstevel@tonic-gate 	return (error);
14110Sstevel@tonic-gate #undef	_LASTMARK
14120Sstevel@tonic-gate }
14130Sstevel@tonic-gate 
14140Sstevel@tonic-gate /*
14150Sstevel@tonic-gate  * Default processing of M_PROTO/M_PCPROTO messages.
14160Sstevel@tonic-gate  * Determine which wakeups and signals are needed.
14170Sstevel@tonic-gate  * This can be replaced by a user-specified procedure for kernel users
14180Sstevel@tonic-gate  * of STREAMS.
14190Sstevel@tonic-gate  */
14200Sstevel@tonic-gate /* ARGSUSED */
14210Sstevel@tonic-gate mblk_t *
14220Sstevel@tonic-gate strrput_proto(vnode_t *vp, mblk_t *mp,
14230Sstevel@tonic-gate     strwakeup_t *wakeups, strsigset_t *firstmsgsigs,
14240Sstevel@tonic-gate     strsigset_t *allmsgsigs, strpollset_t *pollwakeups)
14250Sstevel@tonic-gate {
14260Sstevel@tonic-gate 	*wakeups = RSLEEP;
14270Sstevel@tonic-gate 	*allmsgsigs = 0;
14280Sstevel@tonic-gate 
14290Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
14300Sstevel@tonic-gate 	case M_PROTO:
14310Sstevel@tonic-gate 		if (mp->b_band == 0) {
14320Sstevel@tonic-gate 			*firstmsgsigs = S_INPUT | S_RDNORM;
14330Sstevel@tonic-gate 			*pollwakeups = POLLIN | POLLRDNORM;
14340Sstevel@tonic-gate 		} else {
14350Sstevel@tonic-gate 			*firstmsgsigs = S_INPUT | S_RDBAND;
14360Sstevel@tonic-gate 			*pollwakeups = POLLIN | POLLRDBAND;
14370Sstevel@tonic-gate 		}
14380Sstevel@tonic-gate 		break;
14390Sstevel@tonic-gate 	case M_PCPROTO:
14400Sstevel@tonic-gate 		*firstmsgsigs = S_HIPRI;
14410Sstevel@tonic-gate 		*pollwakeups = POLLPRI;
14420Sstevel@tonic-gate 		break;
14430Sstevel@tonic-gate 	}
14440Sstevel@tonic-gate 	return (mp);
14450Sstevel@tonic-gate }
14460Sstevel@tonic-gate 
14470Sstevel@tonic-gate /*
14480Sstevel@tonic-gate  * Default processing of everything but M_DATA, M_PROTO, M_PCPROTO and
14490Sstevel@tonic-gate  * M_PASSFP messages.
14500Sstevel@tonic-gate  * Determine which wakeups and signals are needed.
14510Sstevel@tonic-gate  * This can be replaced by a user-specified procedure for kernel users
14520Sstevel@tonic-gate  * of STREAMS.
14530Sstevel@tonic-gate  */
14540Sstevel@tonic-gate /* ARGSUSED */
14550Sstevel@tonic-gate mblk_t *
14560Sstevel@tonic-gate strrput_misc(vnode_t *vp, mblk_t *mp,
14570Sstevel@tonic-gate     strwakeup_t *wakeups, strsigset_t *firstmsgsigs,
14580Sstevel@tonic-gate     strsigset_t *allmsgsigs, strpollset_t *pollwakeups)
14590Sstevel@tonic-gate {
14600Sstevel@tonic-gate 	*wakeups = 0;
14610Sstevel@tonic-gate 	*firstmsgsigs = 0;
14620Sstevel@tonic-gate 	*allmsgsigs = 0;
14630Sstevel@tonic-gate 	*pollwakeups = 0;
14640Sstevel@tonic-gate 	return (mp);
14650Sstevel@tonic-gate }
14660Sstevel@tonic-gate 
14670Sstevel@tonic-gate /*
14680Sstevel@tonic-gate  * Stream read put procedure.  Called from downstream driver/module
14690Sstevel@tonic-gate  * with messages for the stream head.  Data, protocol, and in-stream
14700Sstevel@tonic-gate  * signal messages are placed on the queue, others are handled directly.
14710Sstevel@tonic-gate  */
14720Sstevel@tonic-gate int
14730Sstevel@tonic-gate strrput(queue_t *q, mblk_t *bp)
14740Sstevel@tonic-gate {
14750Sstevel@tonic-gate 	struct stdata	*stp;
14760Sstevel@tonic-gate 	ulong_t		rput_opt;
14770Sstevel@tonic-gate 	strwakeup_t	wakeups;
14780Sstevel@tonic-gate 	strsigset_t	firstmsgsigs;	/* Signals if first message on queue */
14790Sstevel@tonic-gate 	strsigset_t	allmsgsigs;	/* Signals for all messages */
14800Sstevel@tonic-gate 	strsigset_t	signals;	/* Signals events to generate */
14810Sstevel@tonic-gate 	strpollset_t	pollwakeups;
14820Sstevel@tonic-gate 	mblk_t		*nextbp;
14830Sstevel@tonic-gate 	uchar_t		band = 0;
14840Sstevel@tonic-gate 	int		hipri_sig;
14850Sstevel@tonic-gate 
14860Sstevel@tonic-gate 	stp = (struct stdata *)q->q_ptr;
14870Sstevel@tonic-gate 	/*
14880Sstevel@tonic-gate 	 * Use rput_opt for optimized access to the SR_ flags except
14890Sstevel@tonic-gate 	 * SR_POLLIN. That flag has to be checked under sd_lock since it
14900Sstevel@tonic-gate 	 * is modified by strpoll().
14910Sstevel@tonic-gate 	 */
14920Sstevel@tonic-gate 	rput_opt = stp->sd_rput_opt;
14930Sstevel@tonic-gate 
14940Sstevel@tonic-gate 	ASSERT(qclaimed(q));
14950Sstevel@tonic-gate 	TRACE_2(TR_FAC_STREAMS_FR, TR_STRRPUT_ENTER,
14960Sstevel@tonic-gate 		"strrput called with message type:q %p bp %p", q, bp);
14970Sstevel@tonic-gate 
14980Sstevel@tonic-gate 	/*
14990Sstevel@tonic-gate 	 * Perform initial processing and pass to the parameterized functions.
15000Sstevel@tonic-gate 	 */
15010Sstevel@tonic-gate 	ASSERT(bp->b_next == NULL);
15020Sstevel@tonic-gate 
15030Sstevel@tonic-gate 	switch (bp->b_datap->db_type) {
15040Sstevel@tonic-gate 	case M_DATA:
15050Sstevel@tonic-gate 		/*
15060Sstevel@tonic-gate 		 * sockfs is the only consumer of STREOF and when it is set,
15070Sstevel@tonic-gate 		 * it implies that the receiver is not interested in receiving
15080Sstevel@tonic-gate 		 * any more data, hence the mblk is freed to prevent unnecessary
15090Sstevel@tonic-gate 		 * message queueing at the stream head.
15100Sstevel@tonic-gate 		 */
15110Sstevel@tonic-gate 		if (stp->sd_flag == STREOF) {
15120Sstevel@tonic-gate 			freemsg(bp);
15130Sstevel@tonic-gate 			return (0);
15140Sstevel@tonic-gate 		}
15150Sstevel@tonic-gate 		if ((rput_opt & SR_IGN_ZEROLEN) &&
15160Sstevel@tonic-gate 		    bp->b_rptr == bp->b_wptr && msgnodata(bp)) {
15170Sstevel@tonic-gate 			/*
15180Sstevel@tonic-gate 			 * Ignore zero-length M_DATA messages. These might be
15190Sstevel@tonic-gate 			 * generated by some transports.
15200Sstevel@tonic-gate 			 * The zero-length M_DATA messages, even if they
15210Sstevel@tonic-gate 			 * are ignored, should effect the atmark tracking and
15220Sstevel@tonic-gate 			 * should wake up a thread sleeping in strwaitmark.
15230Sstevel@tonic-gate 			 */
15240Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
15250Sstevel@tonic-gate 			if (bp->b_flag & MSGMARKNEXT) {
15260Sstevel@tonic-gate 				/*
15270Sstevel@tonic-gate 				 * Record the position of the mark either
15280Sstevel@tonic-gate 				 * in q_last or in STRATMARK.
15290Sstevel@tonic-gate 				 */
15300Sstevel@tonic-gate 				if (q->q_last != NULL) {
15310Sstevel@tonic-gate 					q->q_last->b_flag &= ~MSGNOTMARKNEXT;
15320Sstevel@tonic-gate 					q->q_last->b_flag |= MSGMARKNEXT;
15330Sstevel@tonic-gate 				} else {
15340Sstevel@tonic-gate 					stp->sd_flag &= ~STRNOTATMARK;
15350Sstevel@tonic-gate 					stp->sd_flag |= STRATMARK;
15360Sstevel@tonic-gate 				}
15370Sstevel@tonic-gate 			} else if (bp->b_flag & MSGNOTMARKNEXT) {
15380Sstevel@tonic-gate 				/*
15390Sstevel@tonic-gate 				 * Record that this is not the position of
15400Sstevel@tonic-gate 				 * the mark either in q_last or in
15410Sstevel@tonic-gate 				 * STRNOTATMARK.
15420Sstevel@tonic-gate 				 */
15430Sstevel@tonic-gate 				if (q->q_last != NULL) {
15440Sstevel@tonic-gate 					q->q_last->b_flag &= ~MSGMARKNEXT;
15450Sstevel@tonic-gate 					q->q_last->b_flag |= MSGNOTMARKNEXT;
15460Sstevel@tonic-gate 				} else {
15470Sstevel@tonic-gate 					stp->sd_flag &= ~STRATMARK;
15480Sstevel@tonic-gate 					stp->sd_flag |= STRNOTATMARK;
15490Sstevel@tonic-gate 				}
15500Sstevel@tonic-gate 			}
15510Sstevel@tonic-gate 			if (stp->sd_flag & RSLEEP) {
15520Sstevel@tonic-gate 				stp->sd_flag &= ~RSLEEP;
15530Sstevel@tonic-gate 				cv_broadcast(&q->q_wait);
15540Sstevel@tonic-gate 			}
15550Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
15560Sstevel@tonic-gate 			freemsg(bp);
15570Sstevel@tonic-gate 			return (0);
15580Sstevel@tonic-gate 		}
15590Sstevel@tonic-gate 		wakeups = RSLEEP;
15600Sstevel@tonic-gate 		if (bp->b_band == 0) {
15610Sstevel@tonic-gate 			firstmsgsigs = S_INPUT | S_RDNORM;
15620Sstevel@tonic-gate 			pollwakeups = POLLIN | POLLRDNORM;
15630Sstevel@tonic-gate 		} else {
15640Sstevel@tonic-gate 			firstmsgsigs = S_INPUT | S_RDBAND;
15650Sstevel@tonic-gate 			pollwakeups = POLLIN | POLLRDBAND;
15660Sstevel@tonic-gate 		}
15670Sstevel@tonic-gate 		if (rput_opt & SR_SIGALLDATA)
15680Sstevel@tonic-gate 			allmsgsigs = firstmsgsigs;
15690Sstevel@tonic-gate 		else
15700Sstevel@tonic-gate 			allmsgsigs = 0;
15710Sstevel@tonic-gate 
15720Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
15730Sstevel@tonic-gate 		if ((rput_opt & SR_CONSOL_DATA) &&
15740Sstevel@tonic-gate 		    (bp->b_flag & (MSGMARK|MSGDELIM)) == 0) {
15750Sstevel@tonic-gate 			/*
15760Sstevel@tonic-gate 			 * Consolidate on M_DATA message onto an M_DATA,
15770Sstevel@tonic-gate 			 * M_PROTO, or M_PCPROTO by merging it with q_last.
15780Sstevel@tonic-gate 			 * The consolidation does not take place if
15790Sstevel@tonic-gate 			 * the old message is marked with either of the
15800Sstevel@tonic-gate 			 * marks or the delim flag or if the new
15810Sstevel@tonic-gate 			 * message is marked with MSGMARK. The MSGMARK
15820Sstevel@tonic-gate 			 * check is needed to handle the odd semantics of
15830Sstevel@tonic-gate 			 * MSGMARK where essentially the whole message
15840Sstevel@tonic-gate 			 * is to be treated as marked.
15850Sstevel@tonic-gate 			 * Carry any MSGMARKNEXT  and MSGNOTMARKNEXT from the
15860Sstevel@tonic-gate 			 * new message to the front of the b_cont chain.
15870Sstevel@tonic-gate 			 */
15880Sstevel@tonic-gate 			mblk_t *lbp;
15890Sstevel@tonic-gate 
15900Sstevel@tonic-gate 			lbp = q->q_last;
15910Sstevel@tonic-gate 			if (lbp != NULL &&
15920Sstevel@tonic-gate 			    (lbp->b_datap->db_type == M_DATA ||
15930Sstevel@tonic-gate 			    lbp->b_datap->db_type == M_PROTO ||
15940Sstevel@tonic-gate 			    lbp->b_datap->db_type == M_PCPROTO) &&
15950Sstevel@tonic-gate 			    !(lbp->b_flag & (MSGDELIM|MSGMARK|
15960Sstevel@tonic-gate 			    MSGMARKNEXT))) {
15970Sstevel@tonic-gate 				rmvq_noenab(q, lbp);
15980Sstevel@tonic-gate 				/*
15990Sstevel@tonic-gate 				 * The first message in the b_cont list
16000Sstevel@tonic-gate 				 * tracks MSGMARKNEXT and MSGNOTMARKNEXT.
16010Sstevel@tonic-gate 				 * We need to handle the case where we
16020Sstevel@tonic-gate 				 * are appending
16030Sstevel@tonic-gate 				 *
16040Sstevel@tonic-gate 				 * 1) a MSGMARKNEXT to a MSGNOTMARKNEXT.
16050Sstevel@tonic-gate 				 * 2) a MSGMARKNEXT to a plain message.
16060Sstevel@tonic-gate 				 * 3) a MSGNOTMARKNEXT to a plain message
16070Sstevel@tonic-gate 				 * 4) a MSGNOTMARKNEXT to a MSGNOTMARKNEXT
16080Sstevel@tonic-gate 				 *    message.
16090Sstevel@tonic-gate 				 *
16100Sstevel@tonic-gate 				 * Thus we never append a MSGMARKNEXT or
16110Sstevel@tonic-gate 				 * MSGNOTMARKNEXT to a MSGMARKNEXT message.
16120Sstevel@tonic-gate 				 */
16130Sstevel@tonic-gate 				if (bp->b_flag & MSGMARKNEXT) {
16140Sstevel@tonic-gate 					lbp->b_flag |= MSGMARKNEXT;
16150Sstevel@tonic-gate 					lbp->b_flag &= ~MSGNOTMARKNEXT;
16160Sstevel@tonic-gate 					bp->b_flag &= ~MSGMARKNEXT;
16170Sstevel@tonic-gate 				} else if (bp->b_flag & MSGNOTMARKNEXT) {
16180Sstevel@tonic-gate 					lbp->b_flag |= MSGNOTMARKNEXT;
16190Sstevel@tonic-gate 					bp->b_flag &= ~MSGNOTMARKNEXT;
16200Sstevel@tonic-gate 				}
16210Sstevel@tonic-gate 
16220Sstevel@tonic-gate 				linkb(lbp, bp);
16230Sstevel@tonic-gate 				bp = lbp;
16240Sstevel@tonic-gate 				/*
16250Sstevel@tonic-gate 				 * The new message logically isn't the first
16260Sstevel@tonic-gate 				 * even though the q_first check below thinks
16270Sstevel@tonic-gate 				 * it is. Clear the firstmsgsigs to make it
16280Sstevel@tonic-gate 				 * not appear to be first.
16290Sstevel@tonic-gate 				 */
16300Sstevel@tonic-gate 				firstmsgsigs = 0;
16310Sstevel@tonic-gate 			}
16320Sstevel@tonic-gate 		}
16330Sstevel@tonic-gate 		break;
16340Sstevel@tonic-gate 
16350Sstevel@tonic-gate 	case M_PASSFP:
16360Sstevel@tonic-gate 		wakeups = RSLEEP;
16370Sstevel@tonic-gate 		allmsgsigs = 0;
16380Sstevel@tonic-gate 		if (bp->b_band == 0) {
16390Sstevel@tonic-gate 			firstmsgsigs = S_INPUT | S_RDNORM;
16400Sstevel@tonic-gate 			pollwakeups = POLLIN | POLLRDNORM;
16410Sstevel@tonic-gate 		} else {
16420Sstevel@tonic-gate 			firstmsgsigs = S_INPUT | S_RDBAND;
16430Sstevel@tonic-gate 			pollwakeups = POLLIN | POLLRDBAND;
16440Sstevel@tonic-gate 		}
16450Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
16460Sstevel@tonic-gate 		break;
16470Sstevel@tonic-gate 
16480Sstevel@tonic-gate 	case M_PROTO:
16490Sstevel@tonic-gate 	case M_PCPROTO:
16500Sstevel@tonic-gate 		ASSERT(stp->sd_rprotofunc != NULL);
16510Sstevel@tonic-gate 		bp = (stp->sd_rprotofunc)(stp->sd_vnode, bp,
16520Sstevel@tonic-gate 			&wakeups, &firstmsgsigs, &allmsgsigs, &pollwakeups);
16530Sstevel@tonic-gate #define	ALLSIG	(S_INPUT|S_HIPRI|S_OUTPUT|S_MSG|S_ERROR|S_HANGUP|S_RDNORM|\
16540Sstevel@tonic-gate 		S_WRNORM|S_RDBAND|S_WRBAND|S_BANDURG)
16550Sstevel@tonic-gate #define	ALLPOLL	(POLLIN|POLLPRI|POLLOUT|POLLRDNORM|POLLWRNORM|POLLRDBAND|\
16560Sstevel@tonic-gate 		POLLWRBAND)
16570Sstevel@tonic-gate 
16580Sstevel@tonic-gate 		ASSERT((wakeups & ~(RSLEEP|WSLEEP)) == 0);
16590Sstevel@tonic-gate 		ASSERT((firstmsgsigs & ~ALLSIG) == 0);
16600Sstevel@tonic-gate 		ASSERT((allmsgsigs & ~ALLSIG) == 0);
16610Sstevel@tonic-gate 		ASSERT((pollwakeups & ~ALLPOLL) == 0);
16620Sstevel@tonic-gate 
16630Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
16640Sstevel@tonic-gate 		break;
16650Sstevel@tonic-gate 
16660Sstevel@tonic-gate 	default:
16670Sstevel@tonic-gate 		ASSERT(stp->sd_rmiscfunc != NULL);
16680Sstevel@tonic-gate 		bp = (stp->sd_rmiscfunc)(stp->sd_vnode, bp,
16690Sstevel@tonic-gate 			&wakeups, &firstmsgsigs, &allmsgsigs, &pollwakeups);
16700Sstevel@tonic-gate 		ASSERT((wakeups & ~(RSLEEP|WSLEEP)) == 0);
16710Sstevel@tonic-gate 		ASSERT((firstmsgsigs & ~ALLSIG) == 0);
16720Sstevel@tonic-gate 		ASSERT((allmsgsigs & ~ALLSIG) == 0);
16730Sstevel@tonic-gate 		ASSERT((pollwakeups & ~ALLPOLL) == 0);
16740Sstevel@tonic-gate #undef	ALLSIG
16750Sstevel@tonic-gate #undef	ALLPOLL
16760Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
16770Sstevel@tonic-gate 		break;
16780Sstevel@tonic-gate 	}
16790Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&stp->sd_lock));
16800Sstevel@tonic-gate 
16810Sstevel@tonic-gate 	/* By default generate superset of signals */
16820Sstevel@tonic-gate 	signals = (firstmsgsigs | allmsgsigs);
16830Sstevel@tonic-gate 
16840Sstevel@tonic-gate 	/*
16850Sstevel@tonic-gate 	 * The  proto and misc functions can return multiple messages
16860Sstevel@tonic-gate 	 * as a b_next chain. Such messages are processed separately.
16870Sstevel@tonic-gate 	 */
16880Sstevel@tonic-gate one_more:
16890Sstevel@tonic-gate 	hipri_sig = 0;
16900Sstevel@tonic-gate 	if (bp == NULL) {
16910Sstevel@tonic-gate 		nextbp = NULL;
16920Sstevel@tonic-gate 	} else {
16930Sstevel@tonic-gate 		nextbp = bp->b_next;
16940Sstevel@tonic-gate 		bp->b_next = NULL;
16950Sstevel@tonic-gate 
16960Sstevel@tonic-gate 		switch (bp->b_datap->db_type) {
16970Sstevel@tonic-gate 		case M_PCPROTO:
16980Sstevel@tonic-gate 			/*
16990Sstevel@tonic-gate 			 * Only one priority protocol message is allowed at the
17000Sstevel@tonic-gate 			 * stream head at a time.
17010Sstevel@tonic-gate 			 */
17020Sstevel@tonic-gate 			if (stp->sd_flag & STRPRI) {
17030Sstevel@tonic-gate 				TRACE_0(TR_FAC_STREAMS_FR, TR_STRRPUT_PROTERR,
17040Sstevel@tonic-gate 				    "M_PCPROTO already at head");
17050Sstevel@tonic-gate 				freemsg(bp);
17060Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
17070Sstevel@tonic-gate 				goto done;
17080Sstevel@tonic-gate 			}
17090Sstevel@tonic-gate 			stp->sd_flag |= STRPRI;
17100Sstevel@tonic-gate 			hipri_sig = 1;
17110Sstevel@tonic-gate 			/* FALLTHRU */
17120Sstevel@tonic-gate 		case M_DATA:
17130Sstevel@tonic-gate 		case M_PROTO:
17140Sstevel@tonic-gate 		case M_PASSFP:
17150Sstevel@tonic-gate 			band = bp->b_band;
17160Sstevel@tonic-gate 			/*
17170Sstevel@tonic-gate 			 * Marking doesn't work well when messages
17180Sstevel@tonic-gate 			 * are marked in more than one band.  We only
17190Sstevel@tonic-gate 			 * remember the last message received, even if
17200Sstevel@tonic-gate 			 * it is placed on the queue ahead of other
17210Sstevel@tonic-gate 			 * marked messages.
17220Sstevel@tonic-gate 			 */
17230Sstevel@tonic-gate 			if (bp->b_flag & MSGMARK)
17240Sstevel@tonic-gate 				stp->sd_mark = bp;
17250Sstevel@tonic-gate 			(void) putq(q, bp);
17260Sstevel@tonic-gate 
17270Sstevel@tonic-gate 			/*
17280Sstevel@tonic-gate 			 * If message is a PCPROTO message, always use
17290Sstevel@tonic-gate 			 * firstmsgsigs to determine if a signal should be
17300Sstevel@tonic-gate 			 * sent as strrput is the only place to send
17310Sstevel@tonic-gate 			 * signals for PCPROTO. Other messages are based on
17320Sstevel@tonic-gate 			 * the STRGETINPROG flag. The flag determines if
17330Sstevel@tonic-gate 			 * strrput or (k)strgetmsg will be responsible for
17340Sstevel@tonic-gate 			 * sending the signals, in the firstmsgsigs case.
17350Sstevel@tonic-gate 			 */
17360Sstevel@tonic-gate 			if ((hipri_sig == 1) ||
17370Sstevel@tonic-gate 			    (((stp->sd_flag & STRGETINPROG) == 0) &&
17380Sstevel@tonic-gate 			    (q->q_first == bp)))
17390Sstevel@tonic-gate 				signals = (firstmsgsigs | allmsgsigs);
17400Sstevel@tonic-gate 			else
17410Sstevel@tonic-gate 				signals = allmsgsigs;
17420Sstevel@tonic-gate 			break;
17430Sstevel@tonic-gate 
17440Sstevel@tonic-gate 		default:
17450Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
17460Sstevel@tonic-gate 			(void) strrput_nondata(q, bp);
17470Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
17480Sstevel@tonic-gate 			break;
17490Sstevel@tonic-gate 		}
17500Sstevel@tonic-gate 	}
17510Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&stp->sd_lock));
17520Sstevel@tonic-gate 	/*
17530Sstevel@tonic-gate 	 * Wake sleeping read/getmsg and cancel deferred wakeup
17540Sstevel@tonic-gate 	 */
17550Sstevel@tonic-gate 	if (wakeups & RSLEEP)
17560Sstevel@tonic-gate 		stp->sd_wakeq &= ~RSLEEP;
17570Sstevel@tonic-gate 
17580Sstevel@tonic-gate 	wakeups &= stp->sd_flag;
17590Sstevel@tonic-gate 	if (wakeups & RSLEEP) {
17600Sstevel@tonic-gate 		stp->sd_flag &= ~RSLEEP;
17610Sstevel@tonic-gate 		cv_broadcast(&q->q_wait);
17620Sstevel@tonic-gate 	}
17630Sstevel@tonic-gate 	if (wakeups & WSLEEP) {
17640Sstevel@tonic-gate 		stp->sd_flag &= ~WSLEEP;
17650Sstevel@tonic-gate 		cv_broadcast(&_WR(q)->q_wait);
17660Sstevel@tonic-gate 	}
17670Sstevel@tonic-gate 
17680Sstevel@tonic-gate 	if (pollwakeups != 0) {
17690Sstevel@tonic-gate 		if (pollwakeups == (POLLIN | POLLRDNORM)) {
17700Sstevel@tonic-gate 			/*
17710Sstevel@tonic-gate 			 * Can't use rput_opt since it was not
17720Sstevel@tonic-gate 			 * read when sd_lock was held and SR_POLLIN is changed
17730Sstevel@tonic-gate 			 * by strpoll() under sd_lock.
17740Sstevel@tonic-gate 			 */
17750Sstevel@tonic-gate 			if (!(stp->sd_rput_opt & SR_POLLIN))
17760Sstevel@tonic-gate 				goto no_pollwake;
17770Sstevel@tonic-gate 			stp->sd_rput_opt &= ~SR_POLLIN;
17780Sstevel@tonic-gate 		}
17790Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
17800Sstevel@tonic-gate 		pollwakeup(&stp->sd_pollist, pollwakeups);
17810Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
17820Sstevel@tonic-gate 	}
17830Sstevel@tonic-gate no_pollwake:
17840Sstevel@tonic-gate 
17850Sstevel@tonic-gate 	/*
17860Sstevel@tonic-gate 	 * strsendsig can handle multiple signals with a
17870Sstevel@tonic-gate 	 * single call.
17880Sstevel@tonic-gate 	 */
17890Sstevel@tonic-gate 	if (stp->sd_sigflags & signals)
17900Sstevel@tonic-gate 		strsendsig(stp->sd_siglist, signals, band, 0);
17910Sstevel@tonic-gate 	mutex_exit(&stp->sd_lock);
17920Sstevel@tonic-gate 
17930Sstevel@tonic-gate 
17940Sstevel@tonic-gate done:
17950Sstevel@tonic-gate 	if (nextbp == NULL)
17960Sstevel@tonic-gate 		return (0);
17970Sstevel@tonic-gate 
17980Sstevel@tonic-gate 	/*
17990Sstevel@tonic-gate 	 * Any signals were handled the first time.
18000Sstevel@tonic-gate 	 * Wakeups and pollwakeups are redone to avoid any race
18010Sstevel@tonic-gate 	 * conditions - all the messages are not queued until the
18020Sstevel@tonic-gate 	 * last message has been processed by strrput.
18030Sstevel@tonic-gate 	 */
18040Sstevel@tonic-gate 	bp = nextbp;
18050Sstevel@tonic-gate 	signals = firstmsgsigs = allmsgsigs = 0;
18060Sstevel@tonic-gate 	mutex_enter(&stp->sd_lock);
18070Sstevel@tonic-gate 	goto one_more;
18080Sstevel@tonic-gate }
18090Sstevel@tonic-gate 
18100Sstevel@tonic-gate static void
18110Sstevel@tonic-gate log_dupioc(queue_t *rq, mblk_t *bp)
18120Sstevel@tonic-gate {
18130Sstevel@tonic-gate 	queue_t *wq, *qp;
18140Sstevel@tonic-gate 	char *modnames, *mnp, *dname;
18150Sstevel@tonic-gate 	size_t maxmodstr;
18160Sstevel@tonic-gate 	boolean_t islast;
18170Sstevel@tonic-gate 
18180Sstevel@tonic-gate 	/*
18190Sstevel@tonic-gate 	 * Allocate a buffer large enough to hold the names of nstrpush modules
18200Sstevel@tonic-gate 	 * and one driver, with spaces between and NUL terminator.  If we can't
18210Sstevel@tonic-gate 	 * get memory, then we'll just log the driver name.
18220Sstevel@tonic-gate 	 */
18230Sstevel@tonic-gate 	maxmodstr = nstrpush * (FMNAMESZ + 1);
18240Sstevel@tonic-gate 	mnp = modnames = kmem_alloc(maxmodstr, KM_NOSLEEP);
18250Sstevel@tonic-gate 
18260Sstevel@tonic-gate 	/* march down write side to print log message down to the driver */
18270Sstevel@tonic-gate 	wq = WR(rq);
18280Sstevel@tonic-gate 
18290Sstevel@tonic-gate 	/* make sure q_next doesn't shift around while we're grabbing data */
18300Sstevel@tonic-gate 	claimstr(wq);
18310Sstevel@tonic-gate 	qp = wq->q_next;
18320Sstevel@tonic-gate 	do {
18330Sstevel@tonic-gate 		if ((dname = qp->q_qinfo->qi_minfo->mi_idname) == NULL)
18340Sstevel@tonic-gate 			dname = "?";
18350Sstevel@tonic-gate 		islast = !SAMESTR(qp) || qp->q_next == NULL;
18360Sstevel@tonic-gate 		if (modnames == NULL) {
18370Sstevel@tonic-gate 			/*
18380Sstevel@tonic-gate 			 * If we don't have memory, then get the driver name in
18390Sstevel@tonic-gate 			 * the log where we can see it.  Note that memory
18400Sstevel@tonic-gate 			 * pressure is a possible cause of these sorts of bugs.
18410Sstevel@tonic-gate 			 */
18420Sstevel@tonic-gate 			if (islast) {
18430Sstevel@tonic-gate 				modnames = dname;
18440Sstevel@tonic-gate 				maxmodstr = 0;
18450Sstevel@tonic-gate 			}
18460Sstevel@tonic-gate 		} else {
18470Sstevel@tonic-gate 			mnp += snprintf(mnp, FMNAMESZ + 1, "%s", dname);
18480Sstevel@tonic-gate 			if (!islast)
18490Sstevel@tonic-gate 				*mnp++ = ' ';
18500Sstevel@tonic-gate 		}
18510Sstevel@tonic-gate 		qp = qp->q_next;
18520Sstevel@tonic-gate 	} while (!islast);
18530Sstevel@tonic-gate 	releasestr(wq);
18540Sstevel@tonic-gate 	/* Cannot happen unless stream head is corrupt. */
18550Sstevel@tonic-gate 	ASSERT(modnames != NULL);
18560Sstevel@tonic-gate 	(void) strlog(rq->q_qinfo->qi_minfo->mi_idnum, 0, 1,
18570Sstevel@tonic-gate 	    SL_CONSOLE|SL_TRACE|SL_ERROR,
18580Sstevel@tonic-gate 	    "Warning: stream %p received duplicate %X M_IOC%s; module list: %s",
18590Sstevel@tonic-gate 	    rq->q_ptr, ((struct iocblk *)bp->b_rptr)->ioc_cmd,
18600Sstevel@tonic-gate 	    (DB_TYPE(bp) == M_IOCACK ? "ACK" : "NAK"), modnames);
18610Sstevel@tonic-gate 	if (maxmodstr != 0)
18620Sstevel@tonic-gate 		kmem_free(modnames, maxmodstr);
18630Sstevel@tonic-gate }
18640Sstevel@tonic-gate 
18650Sstevel@tonic-gate int
18660Sstevel@tonic-gate strrput_nondata(queue_t *q, mblk_t *bp)
18670Sstevel@tonic-gate {
18680Sstevel@tonic-gate 	struct stdata *stp;
18690Sstevel@tonic-gate 	struct iocblk *iocbp;
18700Sstevel@tonic-gate 	struct stroptions *sop;
18710Sstevel@tonic-gate 	struct copyreq *reqp;
18720Sstevel@tonic-gate 	struct copyresp *resp;
18730Sstevel@tonic-gate 	unsigned char bpri;
18740Sstevel@tonic-gate 	unsigned char  flushed_already = 0;
18750Sstevel@tonic-gate 
18760Sstevel@tonic-gate 	stp = (struct stdata *)q->q_ptr;
18770Sstevel@tonic-gate 
18780Sstevel@tonic-gate 	ASSERT(!(stp->sd_flag & STPLEX));
18790Sstevel@tonic-gate 	ASSERT(qclaimed(q));
18800Sstevel@tonic-gate 
18810Sstevel@tonic-gate 	switch (bp->b_datap->db_type) {
18820Sstevel@tonic-gate 	case M_ERROR:
18830Sstevel@tonic-gate 		/*
18840Sstevel@tonic-gate 		 * An error has occurred downstream, the errno is in the first
18850Sstevel@tonic-gate 		 * bytes of the message.
18860Sstevel@tonic-gate 		 */
18870Sstevel@tonic-gate 		if ((bp->b_wptr - bp->b_rptr) == 2) {	/* New flavor */
18880Sstevel@tonic-gate 			unsigned char rw = 0;
18890Sstevel@tonic-gate 
18900Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
18910Sstevel@tonic-gate 			if (*bp->b_rptr != NOERROR) {	/* read error */
18920Sstevel@tonic-gate 				if (*bp->b_rptr != 0) {
18930Sstevel@tonic-gate 					if (stp->sd_flag & STRDERR)
18940Sstevel@tonic-gate 						flushed_already |= FLUSHR;
18950Sstevel@tonic-gate 					stp->sd_flag |= STRDERR;
18960Sstevel@tonic-gate 					rw |= FLUSHR;
18970Sstevel@tonic-gate 				} else {
18980Sstevel@tonic-gate 					stp->sd_flag &= ~STRDERR;
18990Sstevel@tonic-gate 				}
19000Sstevel@tonic-gate 				stp->sd_rerror = *bp->b_rptr;
19010Sstevel@tonic-gate 			}
19020Sstevel@tonic-gate 			bp->b_rptr++;
19030Sstevel@tonic-gate 			if (*bp->b_rptr != NOERROR) {	/* write error */
19040Sstevel@tonic-gate 				if (*bp->b_rptr != 0) {
19050Sstevel@tonic-gate 					if (stp->sd_flag & STWRERR)
19060Sstevel@tonic-gate 						flushed_already |= FLUSHW;
19070Sstevel@tonic-gate 					stp->sd_flag |= STWRERR;
19080Sstevel@tonic-gate 					rw |= FLUSHW;
19090Sstevel@tonic-gate 				} else {
19100Sstevel@tonic-gate 					stp->sd_flag &= ~STWRERR;
19110Sstevel@tonic-gate 				}
19120Sstevel@tonic-gate 				stp->sd_werror = *bp->b_rptr;
19130Sstevel@tonic-gate 			}
19140Sstevel@tonic-gate 			if (rw) {
19150Sstevel@tonic-gate 				TRACE_2(TR_FAC_STREAMS_FR, TR_STRRPUT_WAKE,
19160Sstevel@tonic-gate 					"strrput cv_broadcast:q %p, bp %p",
19170Sstevel@tonic-gate 					q, bp);
19180Sstevel@tonic-gate 				cv_broadcast(&q->q_wait); /* readers */
19190Sstevel@tonic-gate 				cv_broadcast(&_WR(q)->q_wait); /* writers */
19200Sstevel@tonic-gate 				cv_broadcast(&stp->sd_monitor); /* ioctllers */
19210Sstevel@tonic-gate 
19220Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
19230Sstevel@tonic-gate 				pollwakeup(&stp->sd_pollist, POLLERR);
19240Sstevel@tonic-gate 				mutex_enter(&stp->sd_lock);
19250Sstevel@tonic-gate 
19260Sstevel@tonic-gate 				if (stp->sd_sigflags & S_ERROR)
19270Sstevel@tonic-gate 					strsendsig(stp->sd_siglist, S_ERROR, 0,
19280Sstevel@tonic-gate 					    ((rw & FLUSHR) ? stp->sd_rerror :
19290Sstevel@tonic-gate 					    stp->sd_werror));
19300Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
19310Sstevel@tonic-gate 				/*
19320Sstevel@tonic-gate 				 * Send the M_FLUSH only
19330Sstevel@tonic-gate 				 * for the first M_ERROR
19340Sstevel@tonic-gate 				 * message on the stream
19350Sstevel@tonic-gate 				 */
19360Sstevel@tonic-gate 				if (flushed_already == rw) {
19370Sstevel@tonic-gate 					freemsg(bp);
19380Sstevel@tonic-gate 					return (0);
19390Sstevel@tonic-gate 				}
19400Sstevel@tonic-gate 
19410Sstevel@tonic-gate 				bp->b_datap->db_type = M_FLUSH;
19420Sstevel@tonic-gate 				*bp->b_rptr = rw;
19430Sstevel@tonic-gate 				bp->b_wptr = bp->b_rptr + 1;
19440Sstevel@tonic-gate 				/*
19450Sstevel@tonic-gate 				 * Protect against the driver
19460Sstevel@tonic-gate 				 * passing up messages after
19470Sstevel@tonic-gate 				 * it has done a qprocsoff
19480Sstevel@tonic-gate 				 */
19490Sstevel@tonic-gate 				if (_OTHERQ(q)->q_next == NULL)
19500Sstevel@tonic-gate 					freemsg(bp);
19510Sstevel@tonic-gate 				else
19520Sstevel@tonic-gate 					qreply(q, bp);
19530Sstevel@tonic-gate 				return (0);
19540Sstevel@tonic-gate 			} else
19550Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
19560Sstevel@tonic-gate 		} else if (*bp->b_rptr != 0) {		/* Old flavor */
19570Sstevel@tonic-gate 				if (stp->sd_flag & (STRDERR|STWRERR))
19580Sstevel@tonic-gate 					flushed_already = FLUSHRW;
19590Sstevel@tonic-gate 				mutex_enter(&stp->sd_lock);
19600Sstevel@tonic-gate 				stp->sd_flag |= (STRDERR|STWRERR);
19610Sstevel@tonic-gate 				stp->sd_rerror = *bp->b_rptr;
19620Sstevel@tonic-gate 				stp->sd_werror = *bp->b_rptr;
19630Sstevel@tonic-gate 				TRACE_2(TR_FAC_STREAMS_FR,
19640Sstevel@tonic-gate 					TR_STRRPUT_WAKE2,
19650Sstevel@tonic-gate 					"strrput wakeup #2:q %p, bp %p", q, bp);
19660Sstevel@tonic-gate 				cv_broadcast(&q->q_wait); /* the readers */
19670Sstevel@tonic-gate 				cv_broadcast(&_WR(q)->q_wait); /* the writers */
19680Sstevel@tonic-gate 				cv_broadcast(&stp->sd_monitor); /* ioctllers */
19690Sstevel@tonic-gate 
19700Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
19710Sstevel@tonic-gate 				pollwakeup(&stp->sd_pollist, POLLERR);
19720Sstevel@tonic-gate 				mutex_enter(&stp->sd_lock);
19730Sstevel@tonic-gate 
19740Sstevel@tonic-gate 				if (stp->sd_sigflags & S_ERROR)
19750Sstevel@tonic-gate 					strsendsig(stp->sd_siglist, S_ERROR, 0,
19760Sstevel@tonic-gate 					    (stp->sd_werror ? stp->sd_werror :
19770Sstevel@tonic-gate 					    stp->sd_rerror));
19780Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
19790Sstevel@tonic-gate 
19800Sstevel@tonic-gate 				/*
19810Sstevel@tonic-gate 				 * Send the M_FLUSH only
19820Sstevel@tonic-gate 				 * for the first M_ERROR
19830Sstevel@tonic-gate 				 * message on the stream
19840Sstevel@tonic-gate 				 */
19850Sstevel@tonic-gate 				if (flushed_already != FLUSHRW) {
19860Sstevel@tonic-gate 					bp->b_datap->db_type = M_FLUSH;
19870Sstevel@tonic-gate 					*bp->b_rptr = FLUSHRW;
19880Sstevel@tonic-gate 					/*
19890Sstevel@tonic-gate 					 * Protect against the driver passing up
19900Sstevel@tonic-gate 					 * messages after it has done a
19910Sstevel@tonic-gate 					 * qprocsoff.
19920Sstevel@tonic-gate 					 */
19930Sstevel@tonic-gate 				if (_OTHERQ(q)->q_next == NULL)
19940Sstevel@tonic-gate 					freemsg(bp);
19950Sstevel@tonic-gate 				else
19960Sstevel@tonic-gate 					qreply(q, bp);
19970Sstevel@tonic-gate 				return (0);
19980Sstevel@tonic-gate 				}
19990Sstevel@tonic-gate 		}
20000Sstevel@tonic-gate 		freemsg(bp);
20010Sstevel@tonic-gate 		return (0);
20020Sstevel@tonic-gate 
20030Sstevel@tonic-gate 	case M_HANGUP:
20040Sstevel@tonic-gate 
20050Sstevel@tonic-gate 		freemsg(bp);
20060Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
20070Sstevel@tonic-gate 		stp->sd_werror = ENXIO;
20080Sstevel@tonic-gate 		stp->sd_flag |= STRHUP;
20090Sstevel@tonic-gate 		stp->sd_flag &= ~(WSLEEP|RSLEEP);
20100Sstevel@tonic-gate 
20110Sstevel@tonic-gate 		/*
20120Sstevel@tonic-gate 		 * send signal if controlling tty
20130Sstevel@tonic-gate 		 */
20140Sstevel@tonic-gate 
20150Sstevel@tonic-gate 		if (stp->sd_sidp) {
20160Sstevel@tonic-gate 			prsignal(stp->sd_sidp, SIGHUP);
20170Sstevel@tonic-gate 			if (stp->sd_sidp != stp->sd_pgidp)
20180Sstevel@tonic-gate 				pgsignal(stp->sd_pgidp, SIGTSTP);
20190Sstevel@tonic-gate 		}
20200Sstevel@tonic-gate 
20210Sstevel@tonic-gate 		/*
20220Sstevel@tonic-gate 		 * wake up read, write, and exception pollers and
20230Sstevel@tonic-gate 		 * reset wakeup mechanism.
20240Sstevel@tonic-gate 		 */
20250Sstevel@tonic-gate 		cv_broadcast(&q->q_wait);	/* the readers */
20260Sstevel@tonic-gate 		cv_broadcast(&_WR(q)->q_wait);	/* the writers */
20270Sstevel@tonic-gate 		cv_broadcast(&stp->sd_monitor);	/* the ioctllers */
20280Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
20290Sstevel@tonic-gate 		strhup(stp);
20300Sstevel@tonic-gate 		return (0);
20310Sstevel@tonic-gate 
20320Sstevel@tonic-gate 	case M_UNHANGUP:
20330Sstevel@tonic-gate 		freemsg(bp);
20340Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
20350Sstevel@tonic-gate 		stp->sd_werror = 0;
20360Sstevel@tonic-gate 		stp->sd_flag &= ~STRHUP;
20370Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
20380Sstevel@tonic-gate 		return (0);
20390Sstevel@tonic-gate 
20400Sstevel@tonic-gate 	case M_SIG:
20410Sstevel@tonic-gate 		/*
20420Sstevel@tonic-gate 		 * Someone downstream wants to post a signal.  The
20430Sstevel@tonic-gate 		 * signal to post is contained in the first byte of the
20440Sstevel@tonic-gate 		 * message.  If the message would go on the front of
20450Sstevel@tonic-gate 		 * the queue, send a signal to the process group
20460Sstevel@tonic-gate 		 * (if not SIGPOLL) or to the siglist processes
20470Sstevel@tonic-gate 		 * (SIGPOLL).  If something is already on the queue,
20480Sstevel@tonic-gate 		 * OR if we are delivering a delayed suspend (*sigh*
20490Sstevel@tonic-gate 		 * another "tty" hack) and there's no one sleeping already,
20500Sstevel@tonic-gate 		 * just enqueue the message.
20510Sstevel@tonic-gate 		 */
20520Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
20530Sstevel@tonic-gate 		if (q->q_first || (*bp->b_rptr == SIGTSTP &&
20540Sstevel@tonic-gate 		    !(stp->sd_flag & RSLEEP))) {
20550Sstevel@tonic-gate 			(void) putq(q, bp);
20560Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
20570Sstevel@tonic-gate 			return (0);
20580Sstevel@tonic-gate 		}
20590Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
20600Sstevel@tonic-gate 		/* FALLTHRU */
20610Sstevel@tonic-gate 
20620Sstevel@tonic-gate 	case M_PCSIG:
20630Sstevel@tonic-gate 		/*
20640Sstevel@tonic-gate 		 * Don't enqueue, just post the signal.
20650Sstevel@tonic-gate 		 */
20660Sstevel@tonic-gate 		strsignal(stp, *bp->b_rptr, 0L);
20670Sstevel@tonic-gate 		freemsg(bp);
20680Sstevel@tonic-gate 		return (0);
20690Sstevel@tonic-gate 
20700Sstevel@tonic-gate 	case M_FLUSH:
20710Sstevel@tonic-gate 		/*
20720Sstevel@tonic-gate 		 * Flush queues.  The indication of which queues to flush
20730Sstevel@tonic-gate 		 * is in the first byte of the message.  If the read queue
20740Sstevel@tonic-gate 		 * is specified, then flush it.  If FLUSHBAND is set, just
20750Sstevel@tonic-gate 		 * flush the band specified by the second byte of the message.
20760Sstevel@tonic-gate 		 *
20770Sstevel@tonic-gate 		 * If a module has issued a M_SETOPT to not flush hi
20780Sstevel@tonic-gate 		 * priority messages off of the stream head, then pass this
20790Sstevel@tonic-gate 		 * flag into the flushq code to preserve such messages.
20800Sstevel@tonic-gate 		 */
20810Sstevel@tonic-gate 
20820Sstevel@tonic-gate 		if (*bp->b_rptr & FLUSHR) {
20830Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
20840Sstevel@tonic-gate 			if (*bp->b_rptr & FLUSHBAND) {
20850Sstevel@tonic-gate 				ASSERT((bp->b_wptr - bp->b_rptr) >= 2);
20860Sstevel@tonic-gate 				flushband(q, *(bp->b_rptr + 1), FLUSHALL);
20870Sstevel@tonic-gate 			} else
20880Sstevel@tonic-gate 				flushq_common(q, FLUSHALL,
20890Sstevel@tonic-gate 				    stp->sd_read_opt & RFLUSHPCPROT);
20900Sstevel@tonic-gate 			if ((q->q_first == NULL) ||
20910Sstevel@tonic-gate 			    (q->q_first->b_datap->db_type < QPCTL))
20920Sstevel@tonic-gate 				stp->sd_flag &= ~STRPRI;
20930Sstevel@tonic-gate 			else {
20940Sstevel@tonic-gate 				ASSERT(stp->sd_flag & STRPRI);
20950Sstevel@tonic-gate 			}
20960Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
20970Sstevel@tonic-gate 		}
20980Sstevel@tonic-gate 		if ((*bp->b_rptr & FLUSHW) && !(bp->b_flag & MSGNOLOOP)) {
20990Sstevel@tonic-gate 			*bp->b_rptr &= ~FLUSHR;
21000Sstevel@tonic-gate 			bp->b_flag |= MSGNOLOOP;
21010Sstevel@tonic-gate 			/*
21020Sstevel@tonic-gate 			 * Protect against the driver passing up
21030Sstevel@tonic-gate 			 * messages after it has done a qprocsoff.
21040Sstevel@tonic-gate 			 */
21050Sstevel@tonic-gate 			if (_OTHERQ(q)->q_next == NULL)
21060Sstevel@tonic-gate 				freemsg(bp);
21070Sstevel@tonic-gate 			else
21080Sstevel@tonic-gate 				qreply(q, bp);
21090Sstevel@tonic-gate 			return (0);
21100Sstevel@tonic-gate 		}
21110Sstevel@tonic-gate 		freemsg(bp);
21120Sstevel@tonic-gate 		return (0);
21130Sstevel@tonic-gate 
21140Sstevel@tonic-gate 	case M_IOCACK:
21150Sstevel@tonic-gate 	case M_IOCNAK:
21160Sstevel@tonic-gate 		iocbp = (struct iocblk *)bp->b_rptr;
21170Sstevel@tonic-gate 		/*
21180Sstevel@tonic-gate 		 * If not waiting for ACK or NAK then just free msg.
21190Sstevel@tonic-gate 		 * If incorrect id sequence number then just free msg.
21200Sstevel@tonic-gate 		 * If already have ACK or NAK for user then this is a
21210Sstevel@tonic-gate 		 *    duplicate, display a warning and free the msg.
21220Sstevel@tonic-gate 		 */
21230Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
21240Sstevel@tonic-gate 		if ((stp->sd_flag & IOCWAIT) == 0 || stp->sd_iocblk ||
21250Sstevel@tonic-gate 		    (stp->sd_iocid != iocbp->ioc_id)) {
21260Sstevel@tonic-gate 			/*
21270Sstevel@tonic-gate 			 * If the ACK/NAK is a dup, display a message
21280Sstevel@tonic-gate 			 * Dup is when sd_iocid == ioc_id, and
21290Sstevel@tonic-gate 			 * sd_iocblk == <valid ptr> or -1 (the former
21300Sstevel@tonic-gate 			 * is when an ioctl has been put on the stream
21310Sstevel@tonic-gate 			 * head, but has not yet been consumed, the
21320Sstevel@tonic-gate 			 * later is when it has been consumed).
21330Sstevel@tonic-gate 			 */
21340Sstevel@tonic-gate 			if ((stp->sd_iocid == iocbp->ioc_id) &&
21350Sstevel@tonic-gate 			    (stp->sd_iocblk != NULL)) {
21360Sstevel@tonic-gate 				log_dupioc(q, bp);
21370Sstevel@tonic-gate 			}
21380Sstevel@tonic-gate 			freemsg(bp);
21390Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
21400Sstevel@tonic-gate 			return (0);
21410Sstevel@tonic-gate 		}
21420Sstevel@tonic-gate 
21430Sstevel@tonic-gate 		/*
21440Sstevel@tonic-gate 		 * Assign ACK or NAK to user and wake up.
21450Sstevel@tonic-gate 		 */
21460Sstevel@tonic-gate 		stp->sd_iocblk = bp;
21470Sstevel@tonic-gate 		cv_broadcast(&stp->sd_monitor);
21480Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
21490Sstevel@tonic-gate 		return (0);
21500Sstevel@tonic-gate 
21510Sstevel@tonic-gate 	case M_COPYIN:
21520Sstevel@tonic-gate 	case M_COPYOUT:
21530Sstevel@tonic-gate 		reqp = (struct copyreq *)bp->b_rptr;
21540Sstevel@tonic-gate 
21550Sstevel@tonic-gate 		/*
21560Sstevel@tonic-gate 		 * If not waiting for ACK or NAK then just fail request.
21570Sstevel@tonic-gate 		 * If already have ACK, NAK, or copy request, then just
21580Sstevel@tonic-gate 		 * fail request.
21590Sstevel@tonic-gate 		 * If incorrect id sequence number then just fail request.
21600Sstevel@tonic-gate 		 */
21610Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
21620Sstevel@tonic-gate 		if ((stp->sd_flag & IOCWAIT) == 0 || stp->sd_iocblk ||
21630Sstevel@tonic-gate 		    (stp->sd_iocid != reqp->cq_id)) {
21640Sstevel@tonic-gate 			if (bp->b_cont) {
21650Sstevel@tonic-gate 				freemsg(bp->b_cont);
21660Sstevel@tonic-gate 				bp->b_cont = NULL;
21670Sstevel@tonic-gate 			}
21680Sstevel@tonic-gate 			bp->b_datap->db_type = M_IOCDATA;
21690Sstevel@tonic-gate 			bp->b_wptr = bp->b_rptr + sizeof (struct copyresp);
21700Sstevel@tonic-gate 			resp = (struct copyresp *)bp->b_rptr;
21710Sstevel@tonic-gate 			resp->cp_rval = (caddr_t)1;	/* failure */
21720Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
21730Sstevel@tonic-gate 			putnext(stp->sd_wrq, bp);
21740Sstevel@tonic-gate 			return (0);
21750Sstevel@tonic-gate 		}
21760Sstevel@tonic-gate 
21770Sstevel@tonic-gate 		/*
21780Sstevel@tonic-gate 		 * Assign copy request to user and wake up.
21790Sstevel@tonic-gate 		 */
21800Sstevel@tonic-gate 		stp->sd_iocblk = bp;
21810Sstevel@tonic-gate 		cv_broadcast(&stp->sd_monitor);
21820Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
21830Sstevel@tonic-gate 		return (0);
21840Sstevel@tonic-gate 
21850Sstevel@tonic-gate 	case M_SETOPTS:
21860Sstevel@tonic-gate 		/*
21870Sstevel@tonic-gate 		 * Set stream head options (read option, write offset,
21880Sstevel@tonic-gate 		 * min/max packet size, and/or high/low water marks for
21890Sstevel@tonic-gate 		 * the read side only).
21900Sstevel@tonic-gate 		 */
21910Sstevel@tonic-gate 
21920Sstevel@tonic-gate 		bpri = 0;
21930Sstevel@tonic-gate 		sop = (struct stroptions *)bp->b_rptr;
21940Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
21950Sstevel@tonic-gate 		if (sop->so_flags & SO_READOPT) {
21960Sstevel@tonic-gate 			switch (sop->so_readopt & RMODEMASK) {
21970Sstevel@tonic-gate 			case RNORM:
21980Sstevel@tonic-gate 				stp->sd_read_opt &= ~(RD_MSGDIS | RD_MSGNODIS);
21990Sstevel@tonic-gate 				break;
22000Sstevel@tonic-gate 
22010Sstevel@tonic-gate 			case RMSGD:
22020Sstevel@tonic-gate 				stp->sd_read_opt =
22030Sstevel@tonic-gate 				    ((stp->sd_read_opt & ~RD_MSGNODIS) |
22040Sstevel@tonic-gate 				    RD_MSGDIS);
22050Sstevel@tonic-gate 				break;
22060Sstevel@tonic-gate 
22070Sstevel@tonic-gate 			case RMSGN:
22080Sstevel@tonic-gate 				stp->sd_read_opt =
22090Sstevel@tonic-gate 				    ((stp->sd_read_opt & ~RD_MSGDIS) |
22100Sstevel@tonic-gate 				    RD_MSGNODIS);
22110Sstevel@tonic-gate 				break;
22120Sstevel@tonic-gate 			}
22130Sstevel@tonic-gate 			switch (sop->so_readopt & RPROTMASK) {
22140Sstevel@tonic-gate 			case RPROTNORM:
22150Sstevel@tonic-gate 				stp->sd_read_opt &= ~(RD_PROTDAT | RD_PROTDIS);
22160Sstevel@tonic-gate 				break;
22170Sstevel@tonic-gate 
22180Sstevel@tonic-gate 			case RPROTDAT:
22190Sstevel@tonic-gate 				stp->sd_read_opt =
22200Sstevel@tonic-gate 				    ((stp->sd_read_opt & ~RD_PROTDIS) |
22210Sstevel@tonic-gate 				    RD_PROTDAT);
22220Sstevel@tonic-gate 				break;
22230Sstevel@tonic-gate 
22240Sstevel@tonic-gate 			case RPROTDIS:
22250Sstevel@tonic-gate 				stp->sd_read_opt =
22260Sstevel@tonic-gate 				    ((stp->sd_read_opt & ~RD_PROTDAT) |
22270Sstevel@tonic-gate 				    RD_PROTDIS);
22280Sstevel@tonic-gate 				break;
22290Sstevel@tonic-gate 			}
22300Sstevel@tonic-gate 			switch (sop->so_readopt & RFLUSHMASK) {
22310Sstevel@tonic-gate 			case RFLUSHPCPROT:
22320Sstevel@tonic-gate 				/*
22330Sstevel@tonic-gate 				 * This sets the stream head to NOT flush
22340Sstevel@tonic-gate 				 * M_PCPROTO messages.
22350Sstevel@tonic-gate 				 */
22360Sstevel@tonic-gate 				stp->sd_read_opt |= RFLUSHPCPROT;
22370Sstevel@tonic-gate 				break;
22380Sstevel@tonic-gate 			}
22390Sstevel@tonic-gate 		}
22400Sstevel@tonic-gate 		if (sop->so_flags & SO_ERROPT) {
22410Sstevel@tonic-gate 			switch (sop->so_erropt & RERRMASK) {
22420Sstevel@tonic-gate 			case RERRNORM:
22430Sstevel@tonic-gate 				stp->sd_flag &= ~STRDERRNONPERSIST;
22440Sstevel@tonic-gate 				break;
22450Sstevel@tonic-gate 			case RERRNONPERSIST:
22460Sstevel@tonic-gate 				stp->sd_flag |= STRDERRNONPERSIST;
22470Sstevel@tonic-gate 				break;
22480Sstevel@tonic-gate 			}
22490Sstevel@tonic-gate 			switch (sop->so_erropt & WERRMASK) {
22500Sstevel@tonic-gate 			case WERRNORM:
22510Sstevel@tonic-gate 				stp->sd_flag &= ~STWRERRNONPERSIST;
22520Sstevel@tonic-gate 				break;
22530Sstevel@tonic-gate 			case WERRNONPERSIST:
22540Sstevel@tonic-gate 				stp->sd_flag |= STWRERRNONPERSIST;
22550Sstevel@tonic-gate 				break;
22560Sstevel@tonic-gate 			}
22570Sstevel@tonic-gate 		}
22580Sstevel@tonic-gate 		if (sop->so_flags & SO_COPYOPT) {
22590Sstevel@tonic-gate 			if (sop->so_copyopt & ZCVMSAFE) {
22600Sstevel@tonic-gate 				stp->sd_copyflag |= STZCVMSAFE;
22610Sstevel@tonic-gate 				stp->sd_copyflag &= ~STZCVMUNSAFE;
22620Sstevel@tonic-gate 			} else if (sop->so_copyopt & ZCVMUNSAFE) {
22630Sstevel@tonic-gate 				stp->sd_copyflag |= STZCVMUNSAFE;
22640Sstevel@tonic-gate 				stp->sd_copyflag &= ~STZCVMSAFE;
22650Sstevel@tonic-gate 			}
22660Sstevel@tonic-gate 
22670Sstevel@tonic-gate 			if (sop->so_copyopt & COPYCACHED) {
22680Sstevel@tonic-gate 				stp->sd_copyflag |= STRCOPYCACHED;
22690Sstevel@tonic-gate 			}
22700Sstevel@tonic-gate 		}
22710Sstevel@tonic-gate 		if (sop->so_flags & SO_WROFF)
22720Sstevel@tonic-gate 			stp->sd_wroff = sop->so_wroff;
2273*898Skais 		if (sop->so_flags & SO_TAIL)
2274*898Skais 			stp->sd_tail = sop->so_tail;
22750Sstevel@tonic-gate 		if (sop->so_flags & SO_MINPSZ)
22760Sstevel@tonic-gate 			q->q_minpsz = sop->so_minpsz;
22770Sstevel@tonic-gate 		if (sop->so_flags & SO_MAXPSZ)
22780Sstevel@tonic-gate 			q->q_maxpsz = sop->so_maxpsz;
22790Sstevel@tonic-gate 		if (sop->so_flags & SO_MAXBLK)
22800Sstevel@tonic-gate 			stp->sd_maxblk = sop->so_maxblk;
22810Sstevel@tonic-gate 		if (sop->so_flags & SO_HIWAT) {
22820Sstevel@tonic-gate 		    if (sop->so_flags & SO_BAND) {
22830Sstevel@tonic-gate 			if (strqset(q, QHIWAT, sop->so_band, sop->so_hiwat))
22840Sstevel@tonic-gate 				cmn_err(CE_WARN,
22850Sstevel@tonic-gate 				    "strrput: could not allocate qband\n");
22860Sstevel@tonic-gate 			else
22870Sstevel@tonic-gate 				bpri = sop->so_band;
22880Sstevel@tonic-gate 		    } else {
22890Sstevel@tonic-gate 			q->q_hiwat = sop->so_hiwat;
22900Sstevel@tonic-gate 		    }
22910Sstevel@tonic-gate 		}
22920Sstevel@tonic-gate 		if (sop->so_flags & SO_LOWAT) {
22930Sstevel@tonic-gate 		    if (sop->so_flags & SO_BAND) {
22940Sstevel@tonic-gate 			if (strqset(q, QLOWAT, sop->so_band, sop->so_lowat))
22950Sstevel@tonic-gate 				cmn_err(CE_WARN,
22960Sstevel@tonic-gate 				    "strrput: could not allocate qband\n");
22970Sstevel@tonic-gate 			else
22980Sstevel@tonic-gate 				bpri = sop->so_band;
22990Sstevel@tonic-gate 		    } else {
23000Sstevel@tonic-gate 			q->q_lowat = sop->so_lowat;
23010Sstevel@tonic-gate 		    }
23020Sstevel@tonic-gate 		}
23030Sstevel@tonic-gate 		if (sop->so_flags & SO_MREADON)
23040Sstevel@tonic-gate 			stp->sd_flag |= SNDMREAD;
23050Sstevel@tonic-gate 		if (sop->so_flags & SO_MREADOFF)
23060Sstevel@tonic-gate 			stp->sd_flag &= ~SNDMREAD;
23070Sstevel@tonic-gate 		if (sop->so_flags & SO_NDELON)
23080Sstevel@tonic-gate 			stp->sd_flag |= OLDNDELAY;
23090Sstevel@tonic-gate 		if (sop->so_flags & SO_NDELOFF)
23100Sstevel@tonic-gate 			stp->sd_flag &= ~OLDNDELAY;
23110Sstevel@tonic-gate 		if (sop->so_flags & SO_ISTTY)
23120Sstevel@tonic-gate 			stp->sd_flag |= STRISTTY;
23130Sstevel@tonic-gate 		if (sop->so_flags & SO_ISNTTY)
23140Sstevel@tonic-gate 			stp->sd_flag &= ~STRISTTY;
23150Sstevel@tonic-gate 		if (sop->so_flags & SO_TOSTOP)
23160Sstevel@tonic-gate 			stp->sd_flag |= STRTOSTOP;
23170Sstevel@tonic-gate 		if (sop->so_flags & SO_TONSTOP)
23180Sstevel@tonic-gate 			stp->sd_flag &= ~STRTOSTOP;
23190Sstevel@tonic-gate 		if (sop->so_flags & SO_DELIM)
23200Sstevel@tonic-gate 			stp->sd_flag |= STRDELIM;
23210Sstevel@tonic-gate 		if (sop->so_flags & SO_NODELIM)
23220Sstevel@tonic-gate 			stp->sd_flag &= ~STRDELIM;
23230Sstevel@tonic-gate 
23240Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
23250Sstevel@tonic-gate 		freemsg(bp);
23260Sstevel@tonic-gate 
23270Sstevel@tonic-gate 		/* Check backenable in case the water marks changed */
23280Sstevel@tonic-gate 		qbackenable(q, bpri);
23290Sstevel@tonic-gate 		return (0);
23300Sstevel@tonic-gate 
23310Sstevel@tonic-gate 	/*
23320Sstevel@tonic-gate 	 * The following set of cases deal with situations where two stream
23330Sstevel@tonic-gate 	 * heads are connected to each other (twisted streams).  These messages
23340Sstevel@tonic-gate 	 * have no meaning at the stream head.
23350Sstevel@tonic-gate 	 */
23360Sstevel@tonic-gate 	case M_BREAK:
23370Sstevel@tonic-gate 	case M_CTL:
23380Sstevel@tonic-gate 	case M_DELAY:
23390Sstevel@tonic-gate 	case M_START:
23400Sstevel@tonic-gate 	case M_STOP:
23410Sstevel@tonic-gate 	case M_IOCDATA:
23420Sstevel@tonic-gate 	case M_STARTI:
23430Sstevel@tonic-gate 	case M_STOPI:
23440Sstevel@tonic-gate 		freemsg(bp);
23450Sstevel@tonic-gate 		return (0);
23460Sstevel@tonic-gate 
23470Sstevel@tonic-gate 	case M_IOCTL:
23480Sstevel@tonic-gate 		/*
23490Sstevel@tonic-gate 		 * Always NAK this condition
23500Sstevel@tonic-gate 		 * (makes no sense)
23510Sstevel@tonic-gate 		 * If there is one or more threads in the read side
23520Sstevel@tonic-gate 		 * rwnext we have to defer the nacking until that thread
23530Sstevel@tonic-gate 		 * returns (in strget).
23540Sstevel@tonic-gate 		 */
23550Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
23560Sstevel@tonic-gate 		if (stp->sd_struiodnak != 0) {
23570Sstevel@tonic-gate 			/*
23580Sstevel@tonic-gate 			 * Defer NAK to the streamhead. Queue at the end
23590Sstevel@tonic-gate 			 * the list.
23600Sstevel@tonic-gate 			 */
23610Sstevel@tonic-gate 			mblk_t *mp = stp->sd_struionak;
23620Sstevel@tonic-gate 
23630Sstevel@tonic-gate 			while (mp && mp->b_next)
23640Sstevel@tonic-gate 				mp = mp->b_next;
23650Sstevel@tonic-gate 			if (mp)
23660Sstevel@tonic-gate 				mp->b_next = bp;
23670Sstevel@tonic-gate 			else
23680Sstevel@tonic-gate 				stp->sd_struionak = bp;
23690Sstevel@tonic-gate 			bp->b_next = NULL;
23700Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
23710Sstevel@tonic-gate 			return (0);
23720Sstevel@tonic-gate 		}
23730Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
23740Sstevel@tonic-gate 
23750Sstevel@tonic-gate 		bp->b_datap->db_type = M_IOCNAK;
23760Sstevel@tonic-gate 		/*
23770Sstevel@tonic-gate 		 * Protect against the driver passing up
23780Sstevel@tonic-gate 		 * messages after it has done a qprocsoff.
23790Sstevel@tonic-gate 		 */
23800Sstevel@tonic-gate 		if (_OTHERQ(q)->q_next == NULL)
23810Sstevel@tonic-gate 			freemsg(bp);
23820Sstevel@tonic-gate 		else
23830Sstevel@tonic-gate 			qreply(q, bp);
23840Sstevel@tonic-gate 		return (0);
23850Sstevel@tonic-gate 
23860Sstevel@tonic-gate 	default:
23870Sstevel@tonic-gate #ifdef DEBUG
23880Sstevel@tonic-gate 		cmn_err(CE_WARN,
23890Sstevel@tonic-gate 			"bad message type %x received at stream head\n",
23900Sstevel@tonic-gate 			bp->b_datap->db_type);
23910Sstevel@tonic-gate #endif
23920Sstevel@tonic-gate 		freemsg(bp);
23930Sstevel@tonic-gate 		return (0);
23940Sstevel@tonic-gate 	}
23950Sstevel@tonic-gate 
23960Sstevel@tonic-gate 	/* NOTREACHED */
23970Sstevel@tonic-gate }
23980Sstevel@tonic-gate 
23990Sstevel@tonic-gate /*
24000Sstevel@tonic-gate  * Check if the stream pointed to by `stp' can be written to, and return an
24010Sstevel@tonic-gate  * error code if not.  If `eiohup' is set, then return EIO if STRHUP is set.
24020Sstevel@tonic-gate  * If `sigpipeok' is set and the SW_SIGPIPE option is enabled on the stream,
24030Sstevel@tonic-gate  * then always return EPIPE and send a SIGPIPE to the invoking thread.
24040Sstevel@tonic-gate  */
24050Sstevel@tonic-gate static int
24060Sstevel@tonic-gate strwriteable(struct stdata *stp, boolean_t eiohup, boolean_t sigpipeok)
24070Sstevel@tonic-gate {
24080Sstevel@tonic-gate 	int error;
24090Sstevel@tonic-gate 
24100Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&stp->sd_lock));
24110Sstevel@tonic-gate 
24120Sstevel@tonic-gate 	/*
24130Sstevel@tonic-gate 	 * For modem support, POSIX states that on writes, EIO should
24140Sstevel@tonic-gate 	 * be returned if the stream has been hung up.
24150Sstevel@tonic-gate 	 */
24160Sstevel@tonic-gate 	if (eiohup && (stp->sd_flag & (STPLEX|STRHUP)) == STRHUP)
24170Sstevel@tonic-gate 		error = EIO;
24180Sstevel@tonic-gate 	else
24190Sstevel@tonic-gate 		error = strgeterr(stp, STRHUP|STPLEX|STWRERR, 0);
24200Sstevel@tonic-gate 
24210Sstevel@tonic-gate 	if (error != 0) {
24220Sstevel@tonic-gate 		if (!(stp->sd_flag & STPLEX) &&
24230Sstevel@tonic-gate 		    (stp->sd_wput_opt & SW_SIGPIPE) && sigpipeok) {
24240Sstevel@tonic-gate 			tsignal(curthread, SIGPIPE);
24250Sstevel@tonic-gate 			error = EPIPE;
24260Sstevel@tonic-gate 		}
24270Sstevel@tonic-gate 	}
24280Sstevel@tonic-gate 
24290Sstevel@tonic-gate 	return (error);
24300Sstevel@tonic-gate }
24310Sstevel@tonic-gate 
24320Sstevel@tonic-gate /*
24330Sstevel@tonic-gate  * Copyin and send data down a stream.
24340Sstevel@tonic-gate  * The caller will allocate and copyin any control part that precedes the
24350Sstevel@tonic-gate  * message and pass than in as mctl.
24360Sstevel@tonic-gate  *
24370Sstevel@tonic-gate  * Caller should *not* hold sd_lock.
24380Sstevel@tonic-gate  * When EWOULDBLOCK is returned the caller has to redo the canputnext
24390Sstevel@tonic-gate  * under sd_lock in order to avoid missing a backenabling wakeup.
24400Sstevel@tonic-gate  *
24410Sstevel@tonic-gate  * Use iosize = -1 to not send any M_DATA. iosize = 0 sends zero-length M_DATA.
24420Sstevel@tonic-gate  *
24430Sstevel@tonic-gate  * Set MSG_IGNFLOW in flags to ignore flow control for hipri messages.
24440Sstevel@tonic-gate  * For sync streams we can only ignore flow control by reverting to using
24450Sstevel@tonic-gate  * putnext.
24460Sstevel@tonic-gate  *
24470Sstevel@tonic-gate  * If sd_maxblk is less than *iosize this routine might return without
24480Sstevel@tonic-gate  * transferring all of *iosize. In all cases, on return *iosize will contain
24490Sstevel@tonic-gate  * the amount of data that was transferred.
24500Sstevel@tonic-gate  */
24510Sstevel@tonic-gate static int
24520Sstevel@tonic-gate strput(struct stdata *stp, mblk_t *mctl, struct uio *uiop, ssize_t *iosize,
24530Sstevel@tonic-gate     int b_flag, int pri, int flags)
24540Sstevel@tonic-gate {
24550Sstevel@tonic-gate 	struiod_t uiod;
24560Sstevel@tonic-gate 	mblk_t *mp;
24570Sstevel@tonic-gate 	queue_t *wqp = stp->sd_wrq;
24580Sstevel@tonic-gate 	int error = 0;
24590Sstevel@tonic-gate 	ssize_t count = *iosize;
24600Sstevel@tonic-gate 	cred_t *cr;
24610Sstevel@tonic-gate 
24620Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&stp->sd_lock));
24630Sstevel@tonic-gate 
24640Sstevel@tonic-gate 	if (uiop != NULL && count >= 0)
24650Sstevel@tonic-gate 		flags |= stp->sd_struiowrq ? STRUIO_POSTPONE : 0;
24660Sstevel@tonic-gate 
24670Sstevel@tonic-gate 	if (!(flags & STRUIO_POSTPONE)) {
24680Sstevel@tonic-gate 		/*
24690Sstevel@tonic-gate 		 * Use regular canputnext, strmakedata, putnext sequence.
24700Sstevel@tonic-gate 		 */
24710Sstevel@tonic-gate 		if (pri == 0) {
24720Sstevel@tonic-gate 			if (!canputnext(wqp) && !(flags & MSG_IGNFLOW)) {
24730Sstevel@tonic-gate 				freemsg(mctl);
24740Sstevel@tonic-gate 				return (EWOULDBLOCK);
24750Sstevel@tonic-gate 			}
24760Sstevel@tonic-gate 		} else {
24770Sstevel@tonic-gate 			if (!(flags & MSG_IGNFLOW) && !bcanputnext(wqp, pri)) {
24780Sstevel@tonic-gate 				freemsg(mctl);
24790Sstevel@tonic-gate 				return (EWOULDBLOCK);
24800Sstevel@tonic-gate 			}
24810Sstevel@tonic-gate 		}
24820Sstevel@tonic-gate 
24830Sstevel@tonic-gate 		if ((error = strmakedata(iosize, uiop, stp, flags,
24840Sstevel@tonic-gate 					&mp)) != 0) {
24850Sstevel@tonic-gate 			freemsg(mctl);
24860Sstevel@tonic-gate 			/*
24870Sstevel@tonic-gate 			 * need to change return code to ENOMEM
24880Sstevel@tonic-gate 			 * so that this is not confused with
24890Sstevel@tonic-gate 			 * flow control, EAGAIN.
24900Sstevel@tonic-gate 			 */
24910Sstevel@tonic-gate 
24920Sstevel@tonic-gate 			if (error == EAGAIN)
24930Sstevel@tonic-gate 				return (ENOMEM);
24940Sstevel@tonic-gate 			else
24950Sstevel@tonic-gate 				return (error);
24960Sstevel@tonic-gate 		}
24970Sstevel@tonic-gate 		if (mctl != NULL) {
24980Sstevel@tonic-gate 			if (mctl->b_cont == NULL)
24990Sstevel@tonic-gate 				mctl->b_cont = mp;
25000Sstevel@tonic-gate 			else if (mp != NULL)
25010Sstevel@tonic-gate 				linkb(mctl, mp);
25020Sstevel@tonic-gate 			mp = mctl;
25030Sstevel@tonic-gate 			/*
25040Sstevel@tonic-gate 			 * Note that for interrupt thread, the CRED() is
25050Sstevel@tonic-gate 			 * NULL. Don't bother with the pid either.
25060Sstevel@tonic-gate 			 */
25070Sstevel@tonic-gate 			if ((cr = CRED()) != NULL) {
25080Sstevel@tonic-gate 				mblk_setcred(mp, cr);
25090Sstevel@tonic-gate 				DB_CPID(mp) = curproc->p_pid;
25100Sstevel@tonic-gate 			}
25110Sstevel@tonic-gate 		} else if (mp == NULL)
25120Sstevel@tonic-gate 			return (0);
25130Sstevel@tonic-gate 
25140Sstevel@tonic-gate 		mp->b_flag |= b_flag;
25150Sstevel@tonic-gate 		mp->b_band = (uchar_t)pri;
25160Sstevel@tonic-gate 
25170Sstevel@tonic-gate 		if (flags & MSG_IGNFLOW) {
25180Sstevel@tonic-gate 			/*
25190Sstevel@tonic-gate 			 * XXX Hack: Don't get stuck running service
25200Sstevel@tonic-gate 			 * procedures. This is needed for sockfs when
25210Sstevel@tonic-gate 			 * sending the unbind message out of the rput
25220Sstevel@tonic-gate 			 * procedure - we don't want a put procedure
25230Sstevel@tonic-gate 			 * to run service procedures.
25240Sstevel@tonic-gate 			 */
25250Sstevel@tonic-gate 			putnext(wqp, mp);
25260Sstevel@tonic-gate 		} else {
25270Sstevel@tonic-gate 			stream_willservice(stp);
25280Sstevel@tonic-gate 			putnext(wqp, mp);
25290Sstevel@tonic-gate 			stream_runservice(stp);
25300Sstevel@tonic-gate 		}
25310Sstevel@tonic-gate 		return (0);
25320Sstevel@tonic-gate 	}
25330Sstevel@tonic-gate 	/*
25340Sstevel@tonic-gate 	 * Stream supports rwnext() for the write side.
25350Sstevel@tonic-gate 	 */
25360Sstevel@tonic-gate 	if ((error = strmakedata(iosize, uiop, stp, flags, &mp)) != 0) {
25370Sstevel@tonic-gate 		freemsg(mctl);
25380Sstevel@tonic-gate 		/*
25390Sstevel@tonic-gate 		 * map EAGAIN to ENOMEM since EAGAIN means "flow controlled".
25400Sstevel@tonic-gate 		 */
25410Sstevel@tonic-gate 		return (error == EAGAIN ? ENOMEM : error);
25420Sstevel@tonic-gate 	}
25430Sstevel@tonic-gate 	if (mctl != NULL) {
25440Sstevel@tonic-gate 		if (mctl->b_cont == NULL)
25450Sstevel@tonic-gate 			mctl->b_cont = mp;
25460Sstevel@tonic-gate 		else if (mp != NULL)
25470Sstevel@tonic-gate 			linkb(mctl, mp);
25480Sstevel@tonic-gate 		mp = mctl;
25490Sstevel@tonic-gate 		/*
25500Sstevel@tonic-gate 		 * Note that for interrupt thread, the CRED() is
25510Sstevel@tonic-gate 		 * NULL.  Don't bother with the pid either.
25520Sstevel@tonic-gate 		 */
25530Sstevel@tonic-gate 		if ((cr = CRED()) != NULL) {
25540Sstevel@tonic-gate 			mblk_setcred(mp, cr);
25550Sstevel@tonic-gate 			DB_CPID(mp) = curproc->p_pid;
25560Sstevel@tonic-gate 		}
25570Sstevel@tonic-gate 	} else if (mp == NULL) {
25580Sstevel@tonic-gate 		return (0);
25590Sstevel@tonic-gate 	}
25600Sstevel@tonic-gate 
25610Sstevel@tonic-gate 	mp->b_flag |= b_flag;
25620Sstevel@tonic-gate 	mp->b_band = (uchar_t)pri;
25630Sstevel@tonic-gate 
25640Sstevel@tonic-gate 	(void) uiodup(uiop, &uiod.d_uio, uiod.d_iov,
25650Sstevel@tonic-gate 		sizeof (uiod.d_iov) / sizeof (*uiod.d_iov));
25660Sstevel@tonic-gate 	uiod.d_uio.uio_offset = 0;
25670Sstevel@tonic-gate 	uiod.d_mp = mp;
25680Sstevel@tonic-gate 	error = rwnext(wqp, &uiod);
25690Sstevel@tonic-gate 	if (! uiod.d_mp) {
25700Sstevel@tonic-gate 		uioskip(uiop, *iosize);
25710Sstevel@tonic-gate 		return (error);
25720Sstevel@tonic-gate 	}
25730Sstevel@tonic-gate 	ASSERT(mp == uiod.d_mp);
25740Sstevel@tonic-gate 	if (error == EINVAL) {
25750Sstevel@tonic-gate 		/*
25760Sstevel@tonic-gate 		 * The stream plumbing must have changed while
25770Sstevel@tonic-gate 		 * we were away, so just turn off rwnext()s.
25780Sstevel@tonic-gate 		 */
25790Sstevel@tonic-gate 		error = 0;
25800Sstevel@tonic-gate 	} else if (error == EBUSY || error == EWOULDBLOCK) {
25810Sstevel@tonic-gate 		/*
25820Sstevel@tonic-gate 		 * Couldn't enter a perimeter or took a page fault,
25830Sstevel@tonic-gate 		 * so fall-back to putnext().
25840Sstevel@tonic-gate 		 */
25850Sstevel@tonic-gate 		error = 0;
25860Sstevel@tonic-gate 	} else {
25870Sstevel@tonic-gate 		freemsg(mp);
25880Sstevel@tonic-gate 		return (error);
25890Sstevel@tonic-gate 	}
25900Sstevel@tonic-gate 	/* Have to check canput before consuming data from the uio */
25910Sstevel@tonic-gate 	if (pri == 0) {
25920Sstevel@tonic-gate 		if (!canputnext(wqp) && !(flags & MSG_IGNFLOW)) {
25930Sstevel@tonic-gate 			freemsg(mp);
25940Sstevel@tonic-gate 			return (EWOULDBLOCK);
25950Sstevel@tonic-gate 		}
25960Sstevel@tonic-gate 	} else {
25970Sstevel@tonic-gate 		if (!bcanputnext(wqp, pri) && !(flags & MSG_IGNFLOW)) {
25980Sstevel@tonic-gate 			freemsg(mp);
25990Sstevel@tonic-gate 			return (EWOULDBLOCK);
26000Sstevel@tonic-gate 		}
26010Sstevel@tonic-gate 	}
26020Sstevel@tonic-gate 	ASSERT(mp == uiod.d_mp);
26030Sstevel@tonic-gate 	/* Copyin data from the uio */
26040Sstevel@tonic-gate 	if ((error = struioget(wqp, mp, &uiod, 0)) != 0) {
26050Sstevel@tonic-gate 		freemsg(mp);
26060Sstevel@tonic-gate 		return (error);
26070Sstevel@tonic-gate 	}
26080Sstevel@tonic-gate 	uioskip(uiop, *iosize);
26090Sstevel@tonic-gate 	if (flags & MSG_IGNFLOW) {
26100Sstevel@tonic-gate 		/*
26110Sstevel@tonic-gate 		 * XXX Hack: Don't get stuck running service procedures.
26120Sstevel@tonic-gate 		 * This is needed for sockfs when sending the unbind message
26130Sstevel@tonic-gate 		 * out of the rput procedure - we don't want a put procedure
26140Sstevel@tonic-gate 		 * to run service procedures.
26150Sstevel@tonic-gate 		 */
26160Sstevel@tonic-gate 		putnext(wqp, mp);
26170Sstevel@tonic-gate 	} else {
26180Sstevel@tonic-gate 		stream_willservice(stp);
26190Sstevel@tonic-gate 		putnext(wqp, mp);
26200Sstevel@tonic-gate 		stream_runservice(stp);
26210Sstevel@tonic-gate 	}
26220Sstevel@tonic-gate 	return (0);
26230Sstevel@tonic-gate }
26240Sstevel@tonic-gate 
26250Sstevel@tonic-gate /*
26260Sstevel@tonic-gate  * Write attempts to break the write request into messages conforming
26270Sstevel@tonic-gate  * with the minimum and maximum packet sizes set downstream.
26280Sstevel@tonic-gate  *
26290Sstevel@tonic-gate  * Write will not block if downstream queue is full and
26300Sstevel@tonic-gate  * O_NDELAY is set, otherwise it will block waiting for the queue to get room.
26310Sstevel@tonic-gate  *
26320Sstevel@tonic-gate  * A write of zero bytes gets packaged into a zero length message and sent
26330Sstevel@tonic-gate  * downstream like any other message.
26340Sstevel@tonic-gate  *
26350Sstevel@tonic-gate  * If buffers of the requested sizes are not available, the write will
26360Sstevel@tonic-gate  * sleep until the buffers become available.
26370Sstevel@tonic-gate  *
26380Sstevel@tonic-gate  * Write (if specified) will supply a write offset in a message if it
26390Sstevel@tonic-gate  * makes sense. This can be specified by downstream modules as part of
26400Sstevel@tonic-gate  * a M_SETOPTS message.  Write will not supply the write offset if it
26410Sstevel@tonic-gate  * cannot supply any data in a buffer.  In other words, write will never
26420Sstevel@tonic-gate  * send down an empty packet due to a write offset.
26430Sstevel@tonic-gate  */
26440Sstevel@tonic-gate /* ARGSUSED2 */
26450Sstevel@tonic-gate int
26460Sstevel@tonic-gate strwrite(struct vnode *vp, struct uio *uiop, cred_t *crp)
26470Sstevel@tonic-gate {
2648741Smasputra 	return (strwrite_common(vp, uiop, crp, 0));
2649741Smasputra }
2650741Smasputra 
2651741Smasputra /* ARGSUSED2 */
2652741Smasputra int
2653741Smasputra strwrite_common(struct vnode *vp, struct uio *uiop, cred_t *crp, int wflag)
2654741Smasputra {
26550Sstevel@tonic-gate 	struct stdata *stp;
26560Sstevel@tonic-gate 	struct queue *wqp;
26570Sstevel@tonic-gate 	ssize_t rmin, rmax;
26580Sstevel@tonic-gate 	ssize_t iosize;
2659741Smasputra 	int waitflag;
26600Sstevel@tonic-gate 	int tempmode;
26610Sstevel@tonic-gate 	int error = 0;
26620Sstevel@tonic-gate 	int b_flag;
26630Sstevel@tonic-gate 
26640Sstevel@tonic-gate 	ASSERT(vp->v_stream);
26650Sstevel@tonic-gate 	stp = vp->v_stream;
26660Sstevel@tonic-gate 
26670Sstevel@tonic-gate 	if (stp->sd_sidp != NULL && stp->sd_vnode->v_type != VFIFO)
26680Sstevel@tonic-gate 		if ((error = straccess(stp, JCWRITE)) != 0)
26690Sstevel@tonic-gate 			return (error);
26700Sstevel@tonic-gate 
26710Sstevel@tonic-gate 	if (stp->sd_flag & (STWRERR|STRHUP|STPLEX)) {
26720Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
26730Sstevel@tonic-gate 		error = strwriteable(stp, B_TRUE, B_TRUE);
26740Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
26750Sstevel@tonic-gate 		if (error != 0)
26760Sstevel@tonic-gate 			return (error);
26770Sstevel@tonic-gate 	}
26780Sstevel@tonic-gate 
26790Sstevel@tonic-gate 	wqp = stp->sd_wrq;
26800Sstevel@tonic-gate 
26810Sstevel@tonic-gate 	/* get these values from them cached in the stream head */
26820Sstevel@tonic-gate 	rmin = stp->sd_qn_minpsz;
26830Sstevel@tonic-gate 	rmax = stp->sd_qn_maxpsz;
26840Sstevel@tonic-gate 
26850Sstevel@tonic-gate 	/*
26860Sstevel@tonic-gate 	 * Check the min/max packet size constraints.  If min packet size
26870Sstevel@tonic-gate 	 * is non-zero, the write cannot be split into multiple messages
26880Sstevel@tonic-gate 	 * and still guarantee the size constraints.
26890Sstevel@tonic-gate 	 */
26900Sstevel@tonic-gate 	TRACE_1(TR_FAC_STREAMS_FR, TR_STRWRITE_IN, "strwrite in:q %p", wqp);
26910Sstevel@tonic-gate 
26920Sstevel@tonic-gate 	ASSERT((rmax >= 0) || (rmax == INFPSZ));
26930Sstevel@tonic-gate 	if (rmax == 0) {
26940Sstevel@tonic-gate 		return (0);
26950Sstevel@tonic-gate 	}
26960Sstevel@tonic-gate 	if (rmin > 0) {
26970Sstevel@tonic-gate 		if (uiop->uio_resid < rmin) {
26980Sstevel@tonic-gate 			TRACE_3(TR_FAC_STREAMS_FR, TR_STRWRITE_OUT,
26990Sstevel@tonic-gate 				"strwrite out:q %p out %d error %d",
27000Sstevel@tonic-gate 				wqp, 0, ERANGE);
27010Sstevel@tonic-gate 			return (ERANGE);
27020Sstevel@tonic-gate 		}
27030Sstevel@tonic-gate 		if ((rmax != INFPSZ) && (uiop->uio_resid > rmax)) {
27040Sstevel@tonic-gate 			TRACE_3(TR_FAC_STREAMS_FR, TR_STRWRITE_OUT,
27050Sstevel@tonic-gate 				"strwrite out:q %p out %d error %d",
27060Sstevel@tonic-gate 				wqp, 1, ERANGE);
27070Sstevel@tonic-gate 			return (ERANGE);
27080Sstevel@tonic-gate 		}
27090Sstevel@tonic-gate 	}
27100Sstevel@tonic-gate 
27110Sstevel@tonic-gate 	/*
27120Sstevel@tonic-gate 	 * Do until count satisfied or error.
27130Sstevel@tonic-gate 	 */
2714741Smasputra 	waitflag = WRITEWAIT | wflag;
27150Sstevel@tonic-gate 	if (stp->sd_flag & OLDNDELAY)
27160Sstevel@tonic-gate 		tempmode = uiop->uio_fmode & ~FNDELAY;
27170Sstevel@tonic-gate 	else
27180Sstevel@tonic-gate 		tempmode = uiop->uio_fmode;
27190Sstevel@tonic-gate 
27200Sstevel@tonic-gate 	if (rmax == INFPSZ)
27210Sstevel@tonic-gate 		rmax = uiop->uio_resid;
27220Sstevel@tonic-gate 
27230Sstevel@tonic-gate 	/*
27240Sstevel@tonic-gate 	 * Note that tempmode does not get used in strput/strmakedata
27250Sstevel@tonic-gate 	 * but only in strwaitq. The other routines use uio_fmode
27260Sstevel@tonic-gate 	 * unmodified.
27270Sstevel@tonic-gate 	 */
27280Sstevel@tonic-gate 
27290Sstevel@tonic-gate 	/* LINTED: constant in conditional context */
27300Sstevel@tonic-gate 	while (1) {	/* breaks when uio_resid reaches zero */
27310Sstevel@tonic-gate 		/*
27320Sstevel@tonic-gate 		 * Determine the size of the next message to be
27330Sstevel@tonic-gate 		 * packaged.  May have to break write into several
27340Sstevel@tonic-gate 		 * messages based on max packet size.
27350Sstevel@tonic-gate 		 */
27360Sstevel@tonic-gate 		iosize = MIN(uiop->uio_resid, rmax);
27370Sstevel@tonic-gate 
27380Sstevel@tonic-gate 		/*
27390Sstevel@tonic-gate 		 * Put block downstream when flow control allows it.
27400Sstevel@tonic-gate 		 */
27410Sstevel@tonic-gate 		if ((stp->sd_flag & STRDELIM) && (uiop->uio_resid == iosize))
27420Sstevel@tonic-gate 			b_flag = MSGDELIM;
27430Sstevel@tonic-gate 		else
27440Sstevel@tonic-gate 			b_flag = 0;
27450Sstevel@tonic-gate 
27460Sstevel@tonic-gate 		for (;;) {
27470Sstevel@tonic-gate 			int done = 0;
27480Sstevel@tonic-gate 
27490Sstevel@tonic-gate 			error = strput(stp, NULL, uiop, &iosize, b_flag,
27500Sstevel@tonic-gate 				0, 0);
27510Sstevel@tonic-gate 			if (error == 0)
27520Sstevel@tonic-gate 				break;
27530Sstevel@tonic-gate 			if (error != EWOULDBLOCK)
27540Sstevel@tonic-gate 				goto out;
27550Sstevel@tonic-gate 
27560Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
27570Sstevel@tonic-gate 			/*
27580Sstevel@tonic-gate 			 * Check for a missed wakeup.
27590Sstevel@tonic-gate 			 * Needed since strput did not hold sd_lock across
27600Sstevel@tonic-gate 			 * the canputnext.
27610Sstevel@tonic-gate 			 */
27620Sstevel@tonic-gate 			if (canputnext(wqp)) {
27630Sstevel@tonic-gate 				/* Try again */
27640Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
27650Sstevel@tonic-gate 				continue;
27660Sstevel@tonic-gate 			}
27670Sstevel@tonic-gate 			TRACE_1(TR_FAC_STREAMS_FR, TR_STRWRITE_WAIT,
27680Sstevel@tonic-gate 				"strwrite wait:q %p wait", wqp);
27690Sstevel@tonic-gate 			if ((error = strwaitq(stp, waitflag, (ssize_t)0,
27700Sstevel@tonic-gate 			    tempmode, -1, &done)) != 0 || done) {
27710Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
27720Sstevel@tonic-gate 				if ((vp->v_type == VFIFO) &&
27730Sstevel@tonic-gate 				    (uiop->uio_fmode & FNDELAY) &&
27740Sstevel@tonic-gate 				    (error == EAGAIN))
27750Sstevel@tonic-gate 					error = 0;
27760Sstevel@tonic-gate 				goto out;
27770Sstevel@tonic-gate 			}
27780Sstevel@tonic-gate 			TRACE_1(TR_FAC_STREAMS_FR, TR_STRWRITE_WAKE,
27790Sstevel@tonic-gate 				"strwrite wake:q %p awakes", wqp);
27800Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
27810Sstevel@tonic-gate 			if (stp->sd_sidp != NULL &&
27820Sstevel@tonic-gate 			    stp->sd_vnode->v_type != VFIFO)
27830Sstevel@tonic-gate 				if (error = straccess(stp, JCWRITE))
27840Sstevel@tonic-gate 					goto out;
27850Sstevel@tonic-gate 		}
27860Sstevel@tonic-gate 		waitflag |= NOINTR;
27870Sstevel@tonic-gate 		TRACE_2(TR_FAC_STREAMS_FR, TR_STRWRITE_RESID,
27880Sstevel@tonic-gate 			"strwrite resid:q %p uiop %p", wqp, uiop);
27890Sstevel@tonic-gate 		if (uiop->uio_resid) {
27900Sstevel@tonic-gate 			/* Recheck for errors - needed for sockets */
27910Sstevel@tonic-gate 			if ((stp->sd_wput_opt & SW_RECHECK_ERR) &&
27920Sstevel@tonic-gate 			    (stp->sd_flag & (STWRERR|STRHUP|STPLEX))) {
27930Sstevel@tonic-gate 				mutex_enter(&stp->sd_lock);
27940Sstevel@tonic-gate 				error = strwriteable(stp, B_FALSE, B_TRUE);
27950Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
27960Sstevel@tonic-gate 				if (error != 0)
27970Sstevel@tonic-gate 					return (error);
27980Sstevel@tonic-gate 			}
27990Sstevel@tonic-gate 			continue;
28000Sstevel@tonic-gate 		}
28010Sstevel@tonic-gate 		break;
28020Sstevel@tonic-gate 	}
28030Sstevel@tonic-gate out:
28040Sstevel@tonic-gate 	/*
28050Sstevel@tonic-gate 	 * For historical reasons, applications expect EAGAIN when a data
28060Sstevel@tonic-gate 	 * mblk_t cannot be allocated, so change ENOMEM back to EAGAIN.
28070Sstevel@tonic-gate 	 */
28080Sstevel@tonic-gate 	if (error == ENOMEM)
28090Sstevel@tonic-gate 		error = EAGAIN;
28100Sstevel@tonic-gate 	TRACE_3(TR_FAC_STREAMS_FR, TR_STRWRITE_OUT,
28110Sstevel@tonic-gate 		"strwrite out:q %p out %d error %d", wqp, 2, error);
28120Sstevel@tonic-gate 	return (error);
28130Sstevel@tonic-gate }
28140Sstevel@tonic-gate 
28150Sstevel@tonic-gate /*
28160Sstevel@tonic-gate  * Stream head write service routine.
28170Sstevel@tonic-gate  * Its job is to wake up any sleeping writers when a queue
28180Sstevel@tonic-gate  * downstream needs data (part of the flow control in putq and getq).
28190Sstevel@tonic-gate  * It also must wake anyone sleeping on a poll().
28200Sstevel@tonic-gate  * For stream head right below mux module, it must also invoke put procedure
28210Sstevel@tonic-gate  * of next downstream module.
28220Sstevel@tonic-gate  */
28230Sstevel@tonic-gate int
28240Sstevel@tonic-gate strwsrv(queue_t *q)
28250Sstevel@tonic-gate {
28260Sstevel@tonic-gate 	struct stdata *stp;
28270Sstevel@tonic-gate 	queue_t *tq;
28280Sstevel@tonic-gate 	qband_t *qbp;
28290Sstevel@tonic-gate 	int i;
28300Sstevel@tonic-gate 	qband_t *myqbp;
28310Sstevel@tonic-gate 	int isevent;
28320Sstevel@tonic-gate 	unsigned char	qbf[NBAND];	/* band flushing backenable flags */
28330Sstevel@tonic-gate 
28340Sstevel@tonic-gate 	TRACE_1(TR_FAC_STREAMS_FR,
28350Sstevel@tonic-gate 		TR_STRWSRV, "strwsrv:q %p", q);
28360Sstevel@tonic-gate 	stp = (struct stdata *)q->q_ptr;
28370Sstevel@tonic-gate 	ASSERT(qclaimed(q));
28380Sstevel@tonic-gate 	mutex_enter(&stp->sd_lock);
28390Sstevel@tonic-gate 	ASSERT(!(stp->sd_flag & STPLEX));
28400Sstevel@tonic-gate 
28410Sstevel@tonic-gate 	if (stp->sd_flag & WSLEEP) {
28420Sstevel@tonic-gate 		stp->sd_flag &= ~WSLEEP;
28430Sstevel@tonic-gate 		cv_broadcast(&q->q_wait);
28440Sstevel@tonic-gate 	}
28450Sstevel@tonic-gate 	mutex_exit(&stp->sd_lock);
28460Sstevel@tonic-gate 
28470Sstevel@tonic-gate 	/* The other end of a stream pipe went away. */
28480Sstevel@tonic-gate 	if ((tq = q->q_next) == NULL) {
28490Sstevel@tonic-gate 		return (0);
28500Sstevel@tonic-gate 	}
28510Sstevel@tonic-gate 
28520Sstevel@tonic-gate 	/* Find the next module forward that has a service procedure */
28530Sstevel@tonic-gate 	claimstr(q);
28540Sstevel@tonic-gate 	tq = q->q_nfsrv;
28550Sstevel@tonic-gate 	ASSERT(tq != NULL);
28560Sstevel@tonic-gate 
28570Sstevel@tonic-gate 	if ((q->q_flag & QBACK)) {
28580Sstevel@tonic-gate 		if ((tq->q_flag & QFULL)) {
28590Sstevel@tonic-gate 			mutex_enter(QLOCK(tq));
28600Sstevel@tonic-gate 			if (!(tq->q_flag & QFULL)) {
28610Sstevel@tonic-gate 				mutex_exit(QLOCK(tq));
28620Sstevel@tonic-gate 				goto wakeup;
28630Sstevel@tonic-gate 			}
28640Sstevel@tonic-gate 			/*
28650Sstevel@tonic-gate 			 * The queue must have become full again. Set QWANTW
28660Sstevel@tonic-gate 			 * again so strwsrv will be back enabled when
28670Sstevel@tonic-gate 			 * the queue becomes non-full next time.
28680Sstevel@tonic-gate 			 */
28690Sstevel@tonic-gate 			tq->q_flag |= QWANTW;
28700Sstevel@tonic-gate 			mutex_exit(QLOCK(tq));
28710Sstevel@tonic-gate 		} else {
28720Sstevel@tonic-gate 		wakeup:
28730Sstevel@tonic-gate 			pollwakeup(&stp->sd_pollist, POLLWRNORM);
28740Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
28750Sstevel@tonic-gate 			if (stp->sd_sigflags & S_WRNORM)
28760Sstevel@tonic-gate 				strsendsig(stp->sd_siglist, S_WRNORM, 0, 0);
28770Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
28780Sstevel@tonic-gate 		}
28790Sstevel@tonic-gate 	}
28800Sstevel@tonic-gate 
28810Sstevel@tonic-gate 	isevent = 0;
28820Sstevel@tonic-gate 	i = 1;
28830Sstevel@tonic-gate 	bzero((caddr_t)qbf, NBAND);
28840Sstevel@tonic-gate 	mutex_enter(QLOCK(tq));
28850Sstevel@tonic-gate 	if ((myqbp = q->q_bandp) != NULL)
28860Sstevel@tonic-gate 		for (qbp = tq->q_bandp; qbp && myqbp; qbp = qbp->qb_next) {
28870Sstevel@tonic-gate 			ASSERT(myqbp);
28880Sstevel@tonic-gate 			if ((myqbp->qb_flag & QB_BACK)) {
28890Sstevel@tonic-gate 				if (qbp->qb_flag & QB_FULL) {
28900Sstevel@tonic-gate 					/*
28910Sstevel@tonic-gate 					 * The band must have become full again.
28920Sstevel@tonic-gate 					 * Set QB_WANTW again so strwsrv will
28930Sstevel@tonic-gate 					 * be back enabled when the band becomes
28940Sstevel@tonic-gate 					 * non-full next time.
28950Sstevel@tonic-gate 					 */
28960Sstevel@tonic-gate 					qbp->qb_flag |= QB_WANTW;
28970Sstevel@tonic-gate 				} else {
28980Sstevel@tonic-gate 					isevent = 1;
28990Sstevel@tonic-gate 					qbf[i] = 1;
29000Sstevel@tonic-gate 				}
29010Sstevel@tonic-gate 			}
29020Sstevel@tonic-gate 			myqbp = myqbp->qb_next;
29030Sstevel@tonic-gate 			i++;
29040Sstevel@tonic-gate 		}
29050Sstevel@tonic-gate 	mutex_exit(QLOCK(tq));
29060Sstevel@tonic-gate 
29070Sstevel@tonic-gate 	if (isevent) {
29080Sstevel@tonic-gate 	    for (i = tq->q_nband; i; i--) {
29090Sstevel@tonic-gate 		if (qbf[i]) {
29100Sstevel@tonic-gate 			pollwakeup(&stp->sd_pollist, POLLWRBAND);
29110Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
29120Sstevel@tonic-gate 			if (stp->sd_sigflags & S_WRBAND)
29130Sstevel@tonic-gate 				strsendsig(stp->sd_siglist, S_WRBAND,
29140Sstevel@tonic-gate 					(uchar_t)i, 0);
29150Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
29160Sstevel@tonic-gate 		}
29170Sstevel@tonic-gate 	    }
29180Sstevel@tonic-gate 	}
29190Sstevel@tonic-gate 
29200Sstevel@tonic-gate 	releasestr(q);
29210Sstevel@tonic-gate 	return (0);
29220Sstevel@tonic-gate }
29230Sstevel@tonic-gate 
29240Sstevel@tonic-gate /*
29250Sstevel@tonic-gate  * Special case of strcopyin/strcopyout for copying
29260Sstevel@tonic-gate  * struct strioctl that can deal with both data
29270Sstevel@tonic-gate  * models.
29280Sstevel@tonic-gate  */
29290Sstevel@tonic-gate 
29300Sstevel@tonic-gate #ifdef	_LP64
29310Sstevel@tonic-gate 
29320Sstevel@tonic-gate static int
29330Sstevel@tonic-gate strcopyin_strioctl(void *from, void *to, int flag, int copyflag)
29340Sstevel@tonic-gate {
29350Sstevel@tonic-gate 	struct	strioctl32 strioc32;
29360Sstevel@tonic-gate 	struct	strioctl *striocp;
29370Sstevel@tonic-gate 
29380Sstevel@tonic-gate 	if (copyflag & U_TO_K) {
29390Sstevel@tonic-gate 		ASSERT((copyflag & K_TO_K) == 0);
29400Sstevel@tonic-gate 
29410Sstevel@tonic-gate 		if ((flag & FMODELS) == DATAMODEL_ILP32) {
29420Sstevel@tonic-gate 			if (copyin(from, &strioc32, sizeof (strioc32)))
29430Sstevel@tonic-gate 				return (EFAULT);
29440Sstevel@tonic-gate 
29450Sstevel@tonic-gate 			striocp = (struct strioctl *)to;
29460Sstevel@tonic-gate 			striocp->ic_cmd	= strioc32.ic_cmd;
29470Sstevel@tonic-gate 			striocp->ic_timout = strioc32.ic_timout;
29480Sstevel@tonic-gate 			striocp->ic_len	= strioc32.ic_len;
29490Sstevel@tonic-gate 			striocp->ic_dp	= (char *)(uintptr_t)strioc32.ic_dp;
29500Sstevel@tonic-gate 
29510Sstevel@tonic-gate 		} else { /* NATIVE data model */
29520Sstevel@tonic-gate 			if (copyin(from, to, sizeof (struct strioctl))) {
29530Sstevel@tonic-gate 				return (EFAULT);
29540Sstevel@tonic-gate 			} else {
29550Sstevel@tonic-gate 				return (0);
29560Sstevel@tonic-gate 			}
29570Sstevel@tonic-gate 		}
29580Sstevel@tonic-gate 	} else {
29590Sstevel@tonic-gate 		ASSERT(copyflag & K_TO_K);
29600Sstevel@tonic-gate 		bcopy(from, to, sizeof (struct strioctl));
29610Sstevel@tonic-gate 	}
29620Sstevel@tonic-gate 	return (0);
29630Sstevel@tonic-gate }
29640Sstevel@tonic-gate 
29650Sstevel@tonic-gate static int
29660Sstevel@tonic-gate strcopyout_strioctl(void *from, void *to, int flag, int copyflag)
29670Sstevel@tonic-gate {
29680Sstevel@tonic-gate 	struct	strioctl32 strioc32;
29690Sstevel@tonic-gate 	struct	strioctl *striocp;
29700Sstevel@tonic-gate 
29710Sstevel@tonic-gate 	if (copyflag & U_TO_K) {
29720Sstevel@tonic-gate 		ASSERT((copyflag & K_TO_K) == 0);
29730Sstevel@tonic-gate 
29740Sstevel@tonic-gate 		if ((flag & FMODELS) == DATAMODEL_ILP32) {
29750Sstevel@tonic-gate 			striocp = (struct strioctl *)from;
29760Sstevel@tonic-gate 			strioc32.ic_cmd	= striocp->ic_cmd;
29770Sstevel@tonic-gate 			strioc32.ic_timout = striocp->ic_timout;
29780Sstevel@tonic-gate 			strioc32.ic_len	= striocp->ic_len;
29790Sstevel@tonic-gate 			strioc32.ic_dp	= (caddr32_t)(uintptr_t)striocp->ic_dp;
29800Sstevel@tonic-gate 			ASSERT((char *)(uintptr_t)strioc32.ic_dp ==
29810Sstevel@tonic-gate 			    striocp->ic_dp);
29820Sstevel@tonic-gate 
29830Sstevel@tonic-gate 			if (copyout(&strioc32, to, sizeof (strioc32)))
29840Sstevel@tonic-gate 				return (EFAULT);
29850Sstevel@tonic-gate 
29860Sstevel@tonic-gate 		} else { /* NATIVE data model */
29870Sstevel@tonic-gate 			if (copyout(from, to, sizeof (struct strioctl))) {
29880Sstevel@tonic-gate 				return (EFAULT);
29890Sstevel@tonic-gate 			} else {
29900Sstevel@tonic-gate 				return (0);
29910Sstevel@tonic-gate 			}
29920Sstevel@tonic-gate 		}
29930Sstevel@tonic-gate 	} else {
29940Sstevel@tonic-gate 		ASSERT(copyflag & K_TO_K);
29950Sstevel@tonic-gate 		bcopy(from, to, sizeof (struct strioctl));
29960Sstevel@tonic-gate 	}
29970Sstevel@tonic-gate 	return (0);
29980Sstevel@tonic-gate }
29990Sstevel@tonic-gate 
30000Sstevel@tonic-gate #else	/* ! _LP64 */
30010Sstevel@tonic-gate 
30020Sstevel@tonic-gate /* ARGSUSED2 */
30030Sstevel@tonic-gate static int
30040Sstevel@tonic-gate strcopyin_strioctl(void *from, void *to, int flag, int copyflag)
30050Sstevel@tonic-gate {
30060Sstevel@tonic-gate 	return (strcopyin(from, to, sizeof (struct strioctl), copyflag));
30070Sstevel@tonic-gate }
30080Sstevel@tonic-gate 
30090Sstevel@tonic-gate /* ARGSUSED2 */
30100Sstevel@tonic-gate static int
30110Sstevel@tonic-gate strcopyout_strioctl(void *from, void *to, int flag, int copyflag)
30120Sstevel@tonic-gate {
30130Sstevel@tonic-gate 	return (strcopyout(from, to, sizeof (struct strioctl), copyflag));
30140Sstevel@tonic-gate }
30150Sstevel@tonic-gate 
30160Sstevel@tonic-gate #endif	/* _LP64 */
30170Sstevel@tonic-gate 
30180Sstevel@tonic-gate /*
30190Sstevel@tonic-gate  * Determine type of job control semantics expected by user.  The
30200Sstevel@tonic-gate  * possibilities are:
30210Sstevel@tonic-gate  *	JCREAD	- Behaves like read() on fd; send SIGTTIN
30220Sstevel@tonic-gate  *	JCWRITE	- Behaves like write() on fd; send SIGTTOU if TOSTOP set
30230Sstevel@tonic-gate  *	JCSETP	- Sets a value in the stream; send SIGTTOU, ignore TOSTOP
30240Sstevel@tonic-gate  *	JCGETP	- Gets a value in the stream; no signals.
30250Sstevel@tonic-gate  * See straccess in strsubr.c for usage of these values.
30260Sstevel@tonic-gate  *
30270Sstevel@tonic-gate  * This routine also returns -1 for I_STR as a special case; the
30280Sstevel@tonic-gate  * caller must call again with the real ioctl number for
30290Sstevel@tonic-gate  * classification.
30300Sstevel@tonic-gate  */
30310Sstevel@tonic-gate static int
30320Sstevel@tonic-gate job_control_type(int cmd)
30330Sstevel@tonic-gate {
30340Sstevel@tonic-gate 	switch (cmd) {
30350Sstevel@tonic-gate 	case I_STR:
30360Sstevel@tonic-gate 		return (-1);
30370Sstevel@tonic-gate 
30380Sstevel@tonic-gate 	case I_RECVFD:
30390Sstevel@tonic-gate 	case I_E_RECVFD:
30400Sstevel@tonic-gate 		return (JCREAD);
30410Sstevel@tonic-gate 
30420Sstevel@tonic-gate 	case I_FDINSERT:
30430Sstevel@tonic-gate 	case I_SENDFD:
30440Sstevel@tonic-gate 		return (JCWRITE);
30450Sstevel@tonic-gate 
30460Sstevel@tonic-gate 	case TCSETA:
30470Sstevel@tonic-gate 	case TCSETAW:
30480Sstevel@tonic-gate 	case TCSETAF:
30490Sstevel@tonic-gate 	case TCSBRK:
30500Sstevel@tonic-gate 	case TCXONC:
30510Sstevel@tonic-gate 	case TCFLSH:
30520Sstevel@tonic-gate 	case TCDSET:	/* Obsolete */
30530Sstevel@tonic-gate 	case TIOCSWINSZ:
30540Sstevel@tonic-gate 	case TCSETS:
30550Sstevel@tonic-gate 	case TCSETSW:
30560Sstevel@tonic-gate 	case TCSETSF:
30570Sstevel@tonic-gate 	case TIOCSETD:
30580Sstevel@tonic-gate 	case TIOCHPCL:
30590Sstevel@tonic-gate 	case TIOCSETP:
30600Sstevel@tonic-gate 	case TIOCSETN:
30610Sstevel@tonic-gate 	case TIOCEXCL:
30620Sstevel@tonic-gate 	case TIOCNXCL:
30630Sstevel@tonic-gate 	case TIOCFLUSH:
30640Sstevel@tonic-gate 	case TIOCSETC:
30650Sstevel@tonic-gate 	case TIOCLBIS:
30660Sstevel@tonic-gate 	case TIOCLBIC:
30670Sstevel@tonic-gate 	case TIOCLSET:
30680Sstevel@tonic-gate 	case TIOCSBRK:
30690Sstevel@tonic-gate 	case TIOCCBRK:
30700Sstevel@tonic-gate 	case TIOCSDTR:
30710Sstevel@tonic-gate 	case TIOCCDTR:
30720Sstevel@tonic-gate 	case TIOCSLTC:
30730Sstevel@tonic-gate 	case TIOCSTOP:
30740Sstevel@tonic-gate 	case TIOCSTART:
30750Sstevel@tonic-gate 	case TIOCSTI:
30760Sstevel@tonic-gate 	case TIOCSPGRP:
30770Sstevel@tonic-gate 	case TIOCMSET:
30780Sstevel@tonic-gate 	case TIOCMBIS:
30790Sstevel@tonic-gate 	case TIOCMBIC:
30800Sstevel@tonic-gate 	case TIOCREMOTE:
30810Sstevel@tonic-gate 	case TIOCSIGNAL:
30820Sstevel@tonic-gate 	case LDSETT:
30830Sstevel@tonic-gate 	case LDSMAP:	/* Obsolete */
30840Sstevel@tonic-gate 	case DIOCSETP:
30850Sstevel@tonic-gate 	case I_FLUSH:
30860Sstevel@tonic-gate 	case I_SRDOPT:
30870Sstevel@tonic-gate 	case I_SETSIG:
30880Sstevel@tonic-gate 	case I_SWROPT:
30890Sstevel@tonic-gate 	case I_FLUSHBAND:
30900Sstevel@tonic-gate 	case I_SETCLTIME:
30910Sstevel@tonic-gate 	case I_SERROPT:
30920Sstevel@tonic-gate 	case I_ESETSIG:
30930Sstevel@tonic-gate 	case FIONBIO:
30940Sstevel@tonic-gate 	case FIOASYNC:
30950Sstevel@tonic-gate 	case FIOSETOWN:
30960Sstevel@tonic-gate 	case JBOOT:	/* Obsolete */
30970Sstevel@tonic-gate 	case JTERM:	/* Obsolete */
30980Sstevel@tonic-gate 	case JTIMOM:	/* Obsolete */
30990Sstevel@tonic-gate 	case JZOMBOOT:	/* Obsolete */
31000Sstevel@tonic-gate 	case JAGENT:	/* Obsolete */
31010Sstevel@tonic-gate 	case JTRUN:	/* Obsolete */
31020Sstevel@tonic-gate 	case JXTPROTO:	/* Obsolete */
31030Sstevel@tonic-gate 		return (JCSETP);
31040Sstevel@tonic-gate 	}
31050Sstevel@tonic-gate 
31060Sstevel@tonic-gate 	return (JCGETP);
31070Sstevel@tonic-gate }
31080Sstevel@tonic-gate 
31090Sstevel@tonic-gate /*
31100Sstevel@tonic-gate  * ioctl for streams
31110Sstevel@tonic-gate  */
31120Sstevel@tonic-gate int
31130Sstevel@tonic-gate strioctl(struct vnode *vp, int cmd, intptr_t arg, int flag, int copyflag,
31140Sstevel@tonic-gate     cred_t *crp, int *rvalp)
31150Sstevel@tonic-gate {
31160Sstevel@tonic-gate 	struct stdata *stp;
31170Sstevel@tonic-gate 	struct strioctl strioc;
31180Sstevel@tonic-gate 	struct uio uio;
31190Sstevel@tonic-gate 	struct iovec iov;
31200Sstevel@tonic-gate 	int access;
31210Sstevel@tonic-gate 	mblk_t *mp;
31220Sstevel@tonic-gate 	int error = 0;
31230Sstevel@tonic-gate 	int done = 0;
31240Sstevel@tonic-gate 	ssize_t	rmin, rmax;
31250Sstevel@tonic-gate 	queue_t *wrq;
31260Sstevel@tonic-gate 	queue_t *rdq;
31270Sstevel@tonic-gate 	boolean_t kioctl = B_FALSE;
31280Sstevel@tonic-gate 
31290Sstevel@tonic-gate 	if (flag & FKIOCTL) {
31300Sstevel@tonic-gate 		copyflag = K_TO_K;
31310Sstevel@tonic-gate 		kioctl = B_TRUE;
31320Sstevel@tonic-gate 	}
31330Sstevel@tonic-gate 	ASSERT(vp->v_stream);
31340Sstevel@tonic-gate 	ASSERT(copyflag == U_TO_K || copyflag == K_TO_K);
31350Sstevel@tonic-gate 	stp = vp->v_stream;
31360Sstevel@tonic-gate 
31370Sstevel@tonic-gate 	TRACE_3(TR_FAC_STREAMS_FR, TR_IOCTL_ENTER,
31380Sstevel@tonic-gate 		"strioctl:stp %p cmd %X arg %lX", stp, cmd, arg);
31390Sstevel@tonic-gate 
31400Sstevel@tonic-gate #ifdef C2_AUDIT
31410Sstevel@tonic-gate 	if (audit_active)
31420Sstevel@tonic-gate 		audit_strioctl(vp, cmd, arg, flag, copyflag, crp, rvalp);
31430Sstevel@tonic-gate #endif
31440Sstevel@tonic-gate 
31450Sstevel@tonic-gate 	/*
31460Sstevel@tonic-gate 	 * If the copy is kernel to kernel, make sure that the FNATIVE
31470Sstevel@tonic-gate 	 * flag is set.  After this it would be a serious error to have
31480Sstevel@tonic-gate 	 * no model flag.
31490Sstevel@tonic-gate 	 */
31500Sstevel@tonic-gate 	if (copyflag == K_TO_K)
31510Sstevel@tonic-gate 		flag = (flag & ~FMODELS) | FNATIVE;
31520Sstevel@tonic-gate 
31530Sstevel@tonic-gate 	ASSERT((flag & FMODELS) != 0);
31540Sstevel@tonic-gate 
31550Sstevel@tonic-gate 	wrq = stp->sd_wrq;
31560Sstevel@tonic-gate 	rdq = _RD(wrq);
31570Sstevel@tonic-gate 
31580Sstevel@tonic-gate 	access = job_control_type(cmd);
31590Sstevel@tonic-gate 
31600Sstevel@tonic-gate 	/* We should never see these here, should be handled by iwscn */
31610Sstevel@tonic-gate 	if (cmd == SRIOCSREDIR || cmd == SRIOCISREDIR)
31620Sstevel@tonic-gate 		return (EINVAL);
31630Sstevel@tonic-gate 
31640Sstevel@tonic-gate 	if (access != -1 && stp->sd_sidp != NULL &&
31650Sstevel@tonic-gate 	    stp->sd_vnode->v_type != VFIFO)
31660Sstevel@tonic-gate 		if (error = straccess(stp, access))
31670Sstevel@tonic-gate 			return (error);
31680Sstevel@tonic-gate 
31690Sstevel@tonic-gate 	/*
31700Sstevel@tonic-gate 	 * Check for sgttyb-related ioctls first, and complain as
31710Sstevel@tonic-gate 	 * necessary.
31720Sstevel@tonic-gate 	 */
31730Sstevel@tonic-gate 	switch (cmd) {
31740Sstevel@tonic-gate 	case TIOCGETP:
31750Sstevel@tonic-gate 	case TIOCSETP:
31760Sstevel@tonic-gate 	case TIOCSETN:
31770Sstevel@tonic-gate 		if (sgttyb_handling >= 2 && !sgttyb_complaint) {
31780Sstevel@tonic-gate 			sgttyb_complaint = B_TRUE;
31790Sstevel@tonic-gate 			cmn_err(CE_NOTE,
31800Sstevel@tonic-gate 			    "application used obsolete TIOC[GS]ET");
31810Sstevel@tonic-gate 		}
31820Sstevel@tonic-gate 		if (sgttyb_handling >= 3) {
31830Sstevel@tonic-gate 			tsignal(curthread, SIGSYS);
31840Sstevel@tonic-gate 			return (EIO);
31850Sstevel@tonic-gate 		}
31860Sstevel@tonic-gate 		break;
31870Sstevel@tonic-gate 	}
31880Sstevel@tonic-gate 
31890Sstevel@tonic-gate 	mutex_enter(&stp->sd_lock);
31900Sstevel@tonic-gate 
31910Sstevel@tonic-gate 	switch (cmd) {
31920Sstevel@tonic-gate 	case I_RECVFD:
31930Sstevel@tonic-gate 	case I_E_RECVFD:
31940Sstevel@tonic-gate 	case I_PEEK:
31950Sstevel@tonic-gate 	case I_NREAD:
31960Sstevel@tonic-gate 	case FIONREAD:
31970Sstevel@tonic-gate 	case FIORDCHK:
31980Sstevel@tonic-gate 	case I_ATMARK:
31990Sstevel@tonic-gate 	case FIONBIO:
32000Sstevel@tonic-gate 	case FIOASYNC:
32010Sstevel@tonic-gate 		if (stp->sd_flag & (STRDERR|STPLEX)) {
32020Sstevel@tonic-gate 			error = strgeterr(stp, STRDERR|STPLEX, 0);
32030Sstevel@tonic-gate 			if (error != 0) {
32040Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
32050Sstevel@tonic-gate 				return (error);
32060Sstevel@tonic-gate 			}
32070Sstevel@tonic-gate 		}
32080Sstevel@tonic-gate 		break;
32090Sstevel@tonic-gate 
32100Sstevel@tonic-gate 	default:
32110Sstevel@tonic-gate 		if (stp->sd_flag & (STRDERR|STWRERR|STPLEX)) {
32120Sstevel@tonic-gate 			error = strgeterr(stp, STRDERR|STWRERR|STPLEX, 0);
32130Sstevel@tonic-gate 			if (error != 0) {
32140Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
32150Sstevel@tonic-gate 				return (error);
32160Sstevel@tonic-gate 			}
32170Sstevel@tonic-gate 		}
32180Sstevel@tonic-gate 	}
32190Sstevel@tonic-gate 
32200Sstevel@tonic-gate 	mutex_exit(&stp->sd_lock);
32210Sstevel@tonic-gate 
32220Sstevel@tonic-gate 	switch (cmd) {
32230Sstevel@tonic-gate 	default:
32240Sstevel@tonic-gate 		/*
32250Sstevel@tonic-gate 		 * The stream head has hardcoded knowledge of a
32260Sstevel@tonic-gate 		 * miscellaneous collection of terminal-, keyboard- and
32270Sstevel@tonic-gate 		 * mouse-related ioctls, enumerated below.  This hardcoded
32280Sstevel@tonic-gate 		 * knowledge allows the stream head to automatically
32290Sstevel@tonic-gate 		 * convert transparent ioctl requests made by userland
32300Sstevel@tonic-gate 		 * programs into I_STR ioctls which many old STREAMS
32310Sstevel@tonic-gate 		 * modules and drivers require.
32320Sstevel@tonic-gate 		 *
32330Sstevel@tonic-gate 		 * No new ioctls should ever be added to this list.
32340Sstevel@tonic-gate 		 * Instead, the STREAMS module or driver should be written
32350Sstevel@tonic-gate 		 * to either handle transparent ioctls or require any
32360Sstevel@tonic-gate 		 * userland programs to use I_STR ioctls (by returning
32370Sstevel@tonic-gate 		 * EINVAL to any transparent ioctl requests).
32380Sstevel@tonic-gate 		 *
32390Sstevel@tonic-gate 		 * More importantly, removing ioctls from this list should
32400Sstevel@tonic-gate 		 * be done with the utmost care, since our STREAMS modules
32410Sstevel@tonic-gate 		 * and drivers *count* on the stream head performing this
32420Sstevel@tonic-gate 		 * conversion, and thus may panic while processing
32430Sstevel@tonic-gate 		 * transparent ioctl request for one of these ioctls (keep
32440Sstevel@tonic-gate 		 * in mind that third party modules and drivers may have
32450Sstevel@tonic-gate 		 * similar problems).
32460Sstevel@tonic-gate 		 */
32470Sstevel@tonic-gate 		if (((cmd & IOCTYPE) == LDIOC) ||
32480Sstevel@tonic-gate 		    ((cmd & IOCTYPE) == tIOC) ||
32490Sstevel@tonic-gate 		    ((cmd & IOCTYPE) == TIOC) ||
32500Sstevel@tonic-gate 		    ((cmd & IOCTYPE) == KIOC) ||
32510Sstevel@tonic-gate 		    ((cmd & IOCTYPE) == MSIOC) ||
32520Sstevel@tonic-gate 		    ((cmd & IOCTYPE) == VUIOC)) {
32530Sstevel@tonic-gate 			/*
32540Sstevel@tonic-gate 			 * The ioctl is a tty ioctl - set up strioc buffer
32550Sstevel@tonic-gate 			 * and call strdoioctl() to do the work.
32560Sstevel@tonic-gate 			 */
32570Sstevel@tonic-gate 			if (stp->sd_flag & STRHUP)
32580Sstevel@tonic-gate 				return (ENXIO);
32590Sstevel@tonic-gate 			strioc.ic_cmd = cmd;
32600Sstevel@tonic-gate 			strioc.ic_timout = INFTIM;
32610Sstevel@tonic-gate 
32620Sstevel@tonic-gate 			switch (cmd) {
32630Sstevel@tonic-gate 
32640Sstevel@tonic-gate 			case TCXONC:
32650Sstevel@tonic-gate 			case TCSBRK:
32660Sstevel@tonic-gate 			case TCFLSH:
32670Sstevel@tonic-gate 			case TCDSET:
32680Sstevel@tonic-gate 				{
32690Sstevel@tonic-gate 				int native_arg = (int)arg;
32700Sstevel@tonic-gate 				strioc.ic_len = sizeof (int);
32710Sstevel@tonic-gate 				strioc.ic_dp = (char *)&native_arg;
32720Sstevel@tonic-gate 				return (strdoioctl(stp, &strioc, flag,
32730Sstevel@tonic-gate 				    K_TO_K, crp, rvalp));
32740Sstevel@tonic-gate 				}
32750Sstevel@tonic-gate 
32760Sstevel@tonic-gate 			case TCSETA:
32770Sstevel@tonic-gate 			case TCSETAW:
32780Sstevel@tonic-gate 			case TCSETAF:
32790Sstevel@tonic-gate 				strioc.ic_len = sizeof (struct termio);
32800Sstevel@tonic-gate 				strioc.ic_dp = (char *)arg;
32810Sstevel@tonic-gate 				return (strdoioctl(stp, &strioc, flag,
32820Sstevel@tonic-gate 					copyflag, crp, rvalp));
32830Sstevel@tonic-gate 
32840Sstevel@tonic-gate 			case TCSETS:
32850Sstevel@tonic-gate 			case TCSETSW:
32860Sstevel@tonic-gate 			case TCSETSF:
32870Sstevel@tonic-gate 				strioc.ic_len = sizeof (struct termios);
32880Sstevel@tonic-gate 				strioc.ic_dp = (char *)arg;
32890Sstevel@tonic-gate 				return (strdoioctl(stp, &strioc, flag,
32900Sstevel@tonic-gate 					copyflag, crp, rvalp));
32910Sstevel@tonic-gate 
32920Sstevel@tonic-gate 			case LDSETT:
32930Sstevel@tonic-gate 				strioc.ic_len = sizeof (struct termcb);
32940Sstevel@tonic-gate 				strioc.ic_dp = (char *)arg;
32950Sstevel@tonic-gate 				return (strdoioctl(stp, &strioc, flag,
32960Sstevel@tonic-gate 					copyflag, crp, rvalp));
32970Sstevel@tonic-gate 
32980Sstevel@tonic-gate 			case TIOCSETP:
32990Sstevel@tonic-gate 				strioc.ic_len = sizeof (struct sgttyb);
33000Sstevel@tonic-gate 				strioc.ic_dp = (char *)arg;
33010Sstevel@tonic-gate 				return (strdoioctl(stp, &strioc, flag,
33020Sstevel@tonic-gate 					copyflag, crp, rvalp));
33030Sstevel@tonic-gate 
33040Sstevel@tonic-gate 			case TIOCSTI:
33050Sstevel@tonic-gate 				if ((flag & FREAD) == 0 &&
33060Sstevel@tonic-gate 				    secpolicy_sti(crp) != 0) {
33070Sstevel@tonic-gate 					return (EPERM);
33080Sstevel@tonic-gate 				}
33090Sstevel@tonic-gate 				if (stp->sd_sidp !=
33100Sstevel@tonic-gate 				    ttoproc(curthread)->p_sessp->s_sidp &&
33110Sstevel@tonic-gate 				    secpolicy_sti(crp) != 0) {
33120Sstevel@tonic-gate 					return (EACCES);
33130Sstevel@tonic-gate 				}
33140Sstevel@tonic-gate 
33150Sstevel@tonic-gate 				strioc.ic_len = sizeof (char);
33160Sstevel@tonic-gate 				strioc.ic_dp = (char *)arg;
33170Sstevel@tonic-gate 				return (strdoioctl(stp, &strioc, flag,
33180Sstevel@tonic-gate 					copyflag, crp, rvalp));
33190Sstevel@tonic-gate 
33200Sstevel@tonic-gate 			case TIOCSWINSZ:
33210Sstevel@tonic-gate 				strioc.ic_len = sizeof (struct winsize);
33220Sstevel@tonic-gate 				strioc.ic_dp = (char *)arg;
33230Sstevel@tonic-gate 				return (strdoioctl(stp, &strioc, flag,
33240Sstevel@tonic-gate 					copyflag, crp, rvalp));
33250Sstevel@tonic-gate 
33260Sstevel@tonic-gate 			case TIOCSSIZE:
33270Sstevel@tonic-gate 				strioc.ic_len = sizeof (struct ttysize);
33280Sstevel@tonic-gate 				strioc.ic_dp = (char *)arg;
33290Sstevel@tonic-gate 				return (strdoioctl(stp, &strioc, flag,
33300Sstevel@tonic-gate 					copyflag, crp, rvalp));
33310Sstevel@tonic-gate 
33320Sstevel@tonic-gate 			case TIOCSSOFTCAR:
33330Sstevel@tonic-gate 			case KIOCTRANS:
33340Sstevel@tonic-gate 			case KIOCTRANSABLE:
33350Sstevel@tonic-gate 			case KIOCCMD:
33360Sstevel@tonic-gate 			case KIOCSDIRECT:
33370Sstevel@tonic-gate 			case KIOCSCOMPAT:
33380Sstevel@tonic-gate 			case KIOCSKABORTEN:
33390Sstevel@tonic-gate 			case KIOCSRPTDELAY:
33400Sstevel@tonic-gate 			case KIOCSRPTRATE:
33410Sstevel@tonic-gate 			case VUIDSFORMAT:
33420Sstevel@tonic-gate 			case TIOCSPPS:
33430Sstevel@tonic-gate 				strioc.ic_len = sizeof (int);
33440Sstevel@tonic-gate 				strioc.ic_dp = (char *)arg;
33450Sstevel@tonic-gate 				return (strdoioctl(stp, &strioc, flag,
33460Sstevel@tonic-gate 					copyflag, crp, rvalp));
33470Sstevel@tonic-gate 
33480Sstevel@tonic-gate 			case KIOCSETKEY:
33490Sstevel@tonic-gate 			case KIOCGETKEY:
33500Sstevel@tonic-gate 				strioc.ic_len = sizeof (struct kiockey);
33510Sstevel@tonic-gate 				strioc.ic_dp = (char *)arg;
33520Sstevel@tonic-gate 				return (strdoioctl(stp, &strioc, flag,
33530Sstevel@tonic-gate 					copyflag, crp, rvalp));
33540Sstevel@tonic-gate 
33550Sstevel@tonic-gate 			case KIOCSKEY:
33560Sstevel@tonic-gate 			case KIOCGKEY:
33570Sstevel@tonic-gate 				strioc.ic_len = sizeof (struct kiockeymap);
33580Sstevel@tonic-gate 				strioc.ic_dp = (char *)arg;
33590Sstevel@tonic-gate 				return (strdoioctl(stp, &strioc, flag,
33600Sstevel@tonic-gate 					copyflag, crp, rvalp));
33610Sstevel@tonic-gate 
33620Sstevel@tonic-gate 			case KIOCSLED:
33630Sstevel@tonic-gate 				/* arg is a pointer to char */
33640Sstevel@tonic-gate 				strioc.ic_len = sizeof (char);
33650Sstevel@tonic-gate 				strioc.ic_dp = (char *)arg;
33660Sstevel@tonic-gate 				return (strdoioctl(stp, &strioc, flag,
33670Sstevel@tonic-gate 					copyflag, crp, rvalp));
33680Sstevel@tonic-gate 
33690Sstevel@tonic-gate 			case MSIOSETPARMS:
33700Sstevel@tonic-gate 				strioc.ic_len = sizeof (Ms_parms);
33710Sstevel@tonic-gate 				strioc.ic_dp = (char *)arg;
33720Sstevel@tonic-gate 				return (strdoioctl(stp, &strioc, flag,
33730Sstevel@tonic-gate 					copyflag, crp, rvalp));
33740Sstevel@tonic-gate 
33750Sstevel@tonic-gate 			case VUIDSADDR:
33760Sstevel@tonic-gate 			case VUIDGADDR:
33770Sstevel@tonic-gate 				strioc.ic_len = sizeof (struct vuid_addr_probe);
33780Sstevel@tonic-gate 				strioc.ic_dp = (char *)arg;
33790Sstevel@tonic-gate 				return (strdoioctl(stp, &strioc, flag,
33800Sstevel@tonic-gate 					copyflag, crp, rvalp));
33810Sstevel@tonic-gate 
33820Sstevel@tonic-gate 			/*
33830Sstevel@tonic-gate 			 * These M_IOCTL's don't require any data to be sent
33840Sstevel@tonic-gate 			 * downstream, and the driver will allocate and link
33850Sstevel@tonic-gate 			 * on its own mblk_t upon M_IOCACK -- thus we set
33860Sstevel@tonic-gate 			 * ic_len to zero and set ic_dp to arg so we know
33870Sstevel@tonic-gate 			 * where to copyout to later.
33880Sstevel@tonic-gate 			 */
33890Sstevel@tonic-gate 			case TIOCGSOFTCAR:
33900Sstevel@tonic-gate 			case TIOCGWINSZ:
33910Sstevel@tonic-gate 			case TIOCGSIZE:
33920Sstevel@tonic-gate 			case KIOCGTRANS:
33930Sstevel@tonic-gate 			case KIOCGTRANSABLE:
33940Sstevel@tonic-gate 			case KIOCTYPE:
33950Sstevel@tonic-gate 			case KIOCGDIRECT:
33960Sstevel@tonic-gate 			case KIOCGCOMPAT:
33970Sstevel@tonic-gate 			case KIOCLAYOUT:
33980Sstevel@tonic-gate 			case KIOCGLED:
33990Sstevel@tonic-gate 			case MSIOGETPARMS:
34000Sstevel@tonic-gate 			case MSIOBUTTONS:
34010Sstevel@tonic-gate 			case VUIDGFORMAT:
34020Sstevel@tonic-gate 			case TIOCGPPS:
34030Sstevel@tonic-gate 			case TIOCGPPSEV:
34040Sstevel@tonic-gate 			case TCGETA:
34050Sstevel@tonic-gate 			case TCGETS:
34060Sstevel@tonic-gate 			case LDGETT:
34070Sstevel@tonic-gate 			case TIOCGETP:
34080Sstevel@tonic-gate 			case KIOCGRPTDELAY:
34090Sstevel@tonic-gate 			case KIOCGRPTRATE:
34100Sstevel@tonic-gate 				strioc.ic_len = 0;
34110Sstevel@tonic-gate 				strioc.ic_dp = (char *)arg;
34120Sstevel@tonic-gate 				return (strdoioctl(stp, &strioc, flag,
34130Sstevel@tonic-gate 					copyflag, crp, rvalp));
34140Sstevel@tonic-gate 			}
34150Sstevel@tonic-gate 		}
34160Sstevel@tonic-gate 
34170Sstevel@tonic-gate 		/*
34180Sstevel@tonic-gate 		 * Unknown cmd - send it down as a transparent ioctl.
34190Sstevel@tonic-gate 		 */
34200Sstevel@tonic-gate 		strioc.ic_cmd = cmd;
34210Sstevel@tonic-gate 		strioc.ic_timout = INFTIM;
34220Sstevel@tonic-gate 		strioc.ic_len = TRANSPARENT;
34230Sstevel@tonic-gate 		strioc.ic_dp = (char *)&arg;
34240Sstevel@tonic-gate 
34250Sstevel@tonic-gate 		return (strdoioctl(stp, &strioc, flag, copyflag, crp, rvalp));
34260Sstevel@tonic-gate 
34270Sstevel@tonic-gate 	case I_STR:
34280Sstevel@tonic-gate 		/*
34290Sstevel@tonic-gate 		 * Stream ioctl.  Read in an strioctl buffer from the user
34300Sstevel@tonic-gate 		 * along with any data specified and send it downstream.
34310Sstevel@tonic-gate 		 * Strdoioctl will wait allow only one ioctl message at
34320Sstevel@tonic-gate 		 * a time, and waits for the acknowledgement.
34330Sstevel@tonic-gate 		 */
34340Sstevel@tonic-gate 
34350Sstevel@tonic-gate 		if (stp->sd_flag & STRHUP)
34360Sstevel@tonic-gate 			return (ENXIO);
34370Sstevel@tonic-gate 
34380Sstevel@tonic-gate 		error = strcopyin_strioctl((void *)arg, &strioc, flag,
34390Sstevel@tonic-gate 		    copyflag);
34400Sstevel@tonic-gate 		if (error != 0)
34410Sstevel@tonic-gate 			return (error);
34420Sstevel@tonic-gate 
34430Sstevel@tonic-gate 		if ((strioc.ic_len < 0) || (strioc.ic_timout < -1))
34440Sstevel@tonic-gate 			return (EINVAL);
34450Sstevel@tonic-gate 
34460Sstevel@tonic-gate 		access = job_control_type(strioc.ic_cmd);
34470Sstevel@tonic-gate 		if (access != -1 && stp->sd_sidp != NULL &&
34480Sstevel@tonic-gate 		    stp->sd_vnode->v_type != VFIFO &&
34490Sstevel@tonic-gate 		    (error = straccess(stp, access)) != 0)
34500Sstevel@tonic-gate 			return (error);
34510Sstevel@tonic-gate 
34520Sstevel@tonic-gate 		/*
34530Sstevel@tonic-gate 		 * The I_STR facility provides a trap door for malicious
34540Sstevel@tonic-gate 		 * code to send down bogus streamio(7I) ioctl commands to
34550Sstevel@tonic-gate 		 * unsuspecting STREAMS modules and drivers which expect to
34560Sstevel@tonic-gate 		 * only get these messages from the stream head.
34570Sstevel@tonic-gate 		 * Explicitly prohibit any streamio ioctls which can be
34580Sstevel@tonic-gate 		 * passed downstream by the stream head.  Note that we do
34590Sstevel@tonic-gate 		 * not block all streamio ioctls because the ioctl
34600Sstevel@tonic-gate 		 * numberspace is not well managed and thus it's possible
34610Sstevel@tonic-gate 		 * that a module or driver's ioctl numbers may accidentally
34620Sstevel@tonic-gate 		 * collide with them.
34630Sstevel@tonic-gate 		 */
34640Sstevel@tonic-gate 		switch (strioc.ic_cmd) {
34650Sstevel@tonic-gate 		case I_LINK:
34660Sstevel@tonic-gate 		case I_PLINK:
34670Sstevel@tonic-gate 		case I_UNLINK:
34680Sstevel@tonic-gate 		case I_PUNLINK:
34690Sstevel@tonic-gate 		case _I_GETPEERCRED:
34700Sstevel@tonic-gate 		case _I_PLINK_LH:
34710Sstevel@tonic-gate 			return (EINVAL);
34720Sstevel@tonic-gate 		}
34730Sstevel@tonic-gate 
34740Sstevel@tonic-gate 		error = strdoioctl(stp, &strioc, flag, copyflag, crp, rvalp);
34750Sstevel@tonic-gate 		if (error == 0) {
34760Sstevel@tonic-gate 			error = strcopyout_strioctl(&strioc, (void *)arg,
34770Sstevel@tonic-gate 			    flag, copyflag);
34780Sstevel@tonic-gate 		}
34790Sstevel@tonic-gate 		return (error);
34800Sstevel@tonic-gate 
34810Sstevel@tonic-gate 	case I_NREAD:
34820Sstevel@tonic-gate 		/*
34830Sstevel@tonic-gate 		 * Return number of bytes of data in first message
34840Sstevel@tonic-gate 		 * in queue in "arg" and return the number of messages
34850Sstevel@tonic-gate 		 * in queue in return value.
34860Sstevel@tonic-gate 		 */
34870Sstevel@tonic-gate 	    {
34880Sstevel@tonic-gate 		size_t	size;
34890Sstevel@tonic-gate 		int	retval;
34900Sstevel@tonic-gate 		int	count = 0;
34910Sstevel@tonic-gate 
34920Sstevel@tonic-gate 		mutex_enter(QLOCK(rdq));
34930Sstevel@tonic-gate 
34940Sstevel@tonic-gate 		size = msgdsize(rdq->q_first);
34950Sstevel@tonic-gate 		for (mp = rdq->q_first; mp != NULL; mp = mp->b_next)
34960Sstevel@tonic-gate 			count++;
34970Sstevel@tonic-gate 
34980Sstevel@tonic-gate 		mutex_exit(QLOCK(rdq));
34990Sstevel@tonic-gate 		if (stp->sd_struiordq) {
35000Sstevel@tonic-gate 			infod_t infod;
35010Sstevel@tonic-gate 
35020Sstevel@tonic-gate 			infod.d_cmd = INFOD_COUNT;
35030Sstevel@tonic-gate 			infod.d_count = 0;
35040Sstevel@tonic-gate 			if (count == 0) {
35050Sstevel@tonic-gate 				infod.d_cmd |= INFOD_FIRSTBYTES;
35060Sstevel@tonic-gate 				infod.d_bytes = 0;
35070Sstevel@tonic-gate 			}
35080Sstevel@tonic-gate 			infod.d_res = 0;
35090Sstevel@tonic-gate 			(void) infonext(rdq, &infod);
35100Sstevel@tonic-gate 			count += infod.d_count;
35110Sstevel@tonic-gate 			if (infod.d_res & INFOD_FIRSTBYTES)
35120Sstevel@tonic-gate 				size = infod.d_bytes;
35130Sstevel@tonic-gate 		}
35140Sstevel@tonic-gate 
35150Sstevel@tonic-gate 		/*
35160Sstevel@tonic-gate 		 * Drop down from size_t to the "int" required by the
35170Sstevel@tonic-gate 		 * interface.  Cap at INT_MAX.
35180Sstevel@tonic-gate 		 */
35190Sstevel@tonic-gate 		retval = MIN(size, INT_MAX);
35200Sstevel@tonic-gate 		error = strcopyout(&retval, (void *)arg, sizeof (retval),
35210Sstevel@tonic-gate 		    copyflag);
35220Sstevel@tonic-gate 		if (!error)
35230Sstevel@tonic-gate 			*rvalp = count;
35240Sstevel@tonic-gate 		return (error);
35250Sstevel@tonic-gate 	    }
35260Sstevel@tonic-gate 
35270Sstevel@tonic-gate 	case FIONREAD:
35280Sstevel@tonic-gate 		/*
35290Sstevel@tonic-gate 		 * Return number of bytes of data in all data messages
35300Sstevel@tonic-gate 		 * in queue in "arg".
35310Sstevel@tonic-gate 		 */
35320Sstevel@tonic-gate 	    {
35330Sstevel@tonic-gate 		size_t	size = 0;
35340Sstevel@tonic-gate 		int	retval;
35350Sstevel@tonic-gate 
35360Sstevel@tonic-gate 		mutex_enter(QLOCK(rdq));
35370Sstevel@tonic-gate 		for (mp = rdq->q_first; mp != NULL; mp = mp->b_next)
35380Sstevel@tonic-gate 			size += msgdsize(mp);
35390Sstevel@tonic-gate 		mutex_exit(QLOCK(rdq));
35400Sstevel@tonic-gate 
35410Sstevel@tonic-gate 		if (stp->sd_struiordq) {
35420Sstevel@tonic-gate 			infod_t infod;
35430Sstevel@tonic-gate 
35440Sstevel@tonic-gate 			infod.d_cmd = INFOD_BYTES;
35450Sstevel@tonic-gate 			infod.d_res = 0;
35460Sstevel@tonic-gate 			infod.d_bytes = 0;
35470Sstevel@tonic-gate 			(void) infonext(rdq, &infod);
35480Sstevel@tonic-gate 			size += infod.d_bytes;
35490Sstevel@tonic-gate 		}
35500Sstevel@tonic-gate 
35510Sstevel@tonic-gate 		/*
35520Sstevel@tonic-gate 		 * Drop down from size_t to the "int" required by the
35530Sstevel@tonic-gate 		 * interface.  Cap at INT_MAX.
35540Sstevel@tonic-gate 		 */
35550Sstevel@tonic-gate 		retval = MIN(size, INT_MAX);
35560Sstevel@tonic-gate 		error = strcopyout(&retval, (void *)arg, sizeof (retval),
35570Sstevel@tonic-gate 		    copyflag);
35580Sstevel@tonic-gate 
35590Sstevel@tonic-gate 		*rvalp = 0;
35600Sstevel@tonic-gate 		return (error);
35610Sstevel@tonic-gate 	    }
35620Sstevel@tonic-gate 	case FIORDCHK:
35630Sstevel@tonic-gate 		/*
35640Sstevel@tonic-gate 		 * FIORDCHK does not use arg value (like FIONREAD),
35650Sstevel@tonic-gate 		 * instead a count is returned. I_NREAD value may
35660Sstevel@tonic-gate 		 * not be accurate but safe. The real thing to do is
35670Sstevel@tonic-gate 		 * to add the msgdsizes of all data  messages until
35680Sstevel@tonic-gate 		 * a non-data message.
35690Sstevel@tonic-gate 		 */
35700Sstevel@tonic-gate 	    {
35710Sstevel@tonic-gate 		size_t size = 0;
35720Sstevel@tonic-gate 
35730Sstevel@tonic-gate 		mutex_enter(QLOCK(rdq));
35740Sstevel@tonic-gate 		for (mp = rdq->q_first; mp != NULL; mp = mp->b_next)
35750Sstevel@tonic-gate 			size += msgdsize(mp);
35760Sstevel@tonic-gate 		mutex_exit(QLOCK(rdq));
35770Sstevel@tonic-gate 
35780Sstevel@tonic-gate 		if (stp->sd_struiordq) {
35790Sstevel@tonic-gate 			infod_t infod;
35800Sstevel@tonic-gate 
35810Sstevel@tonic-gate 			infod.d_cmd = INFOD_BYTES;
35820Sstevel@tonic-gate 			infod.d_res = 0;
35830Sstevel@tonic-gate 			infod.d_bytes = 0;
35840Sstevel@tonic-gate 			(void) infonext(rdq, &infod);
35850Sstevel@tonic-gate 			size += infod.d_bytes;
35860Sstevel@tonic-gate 		}
35870Sstevel@tonic-gate 
35880Sstevel@tonic-gate 		/*
35890Sstevel@tonic-gate 		 * Since ioctl returns an int, and memory sizes under
35900Sstevel@tonic-gate 		 * LP64 may not fit, we return INT_MAX if the count was
35910Sstevel@tonic-gate 		 * actually greater.
35920Sstevel@tonic-gate 		 */
35930Sstevel@tonic-gate 		*rvalp = MIN(size, INT_MAX);
35940Sstevel@tonic-gate 		return (0);
35950Sstevel@tonic-gate 	    }
35960Sstevel@tonic-gate 
35970Sstevel@tonic-gate 	case I_FIND:
35980Sstevel@tonic-gate 		/*
35990Sstevel@tonic-gate 		 * Get module name.
36000Sstevel@tonic-gate 		 */
36010Sstevel@tonic-gate 	    {
36020Sstevel@tonic-gate 		char mname[FMNAMESZ + 1];
36030Sstevel@tonic-gate 		queue_t *q;
36040Sstevel@tonic-gate 
36050Sstevel@tonic-gate 		error = (copyflag & U_TO_K ? copyinstr : copystr)((void *)arg,
36060Sstevel@tonic-gate 		    mname, FMNAMESZ + 1, NULL);
36070Sstevel@tonic-gate 		if (error)
36080Sstevel@tonic-gate 			return ((error == ENAMETOOLONG) ? EINVAL : EFAULT);
36090Sstevel@tonic-gate 
36100Sstevel@tonic-gate 		/*
36110Sstevel@tonic-gate 		 * Return EINVAL if we're handed a bogus module name.
36120Sstevel@tonic-gate 		 */
36130Sstevel@tonic-gate 		if (fmodsw_find(mname, FMODSW_LOAD) == NULL) {
36140Sstevel@tonic-gate 			TRACE_0(TR_FAC_STREAMS_FR,
36150Sstevel@tonic-gate 				TR_I_CANT_FIND, "couldn't I_FIND");
36160Sstevel@tonic-gate 			return (EINVAL);
36170Sstevel@tonic-gate 		}
36180Sstevel@tonic-gate 
36190Sstevel@tonic-gate 		*rvalp = 0;
36200Sstevel@tonic-gate 
36210Sstevel@tonic-gate 		/* Look downstream to see if module is there. */
36220Sstevel@tonic-gate 		claimstr(stp->sd_wrq);
36230Sstevel@tonic-gate 		for (q = stp->sd_wrq->q_next; q; q = q->q_next) {
36240Sstevel@tonic-gate 			if (q->q_flag&QREADR) {
36250Sstevel@tonic-gate 				q = NULL;
36260Sstevel@tonic-gate 				break;
36270Sstevel@tonic-gate 			}
36280Sstevel@tonic-gate 			if (strcmp(mname, q->q_qinfo->qi_minfo->mi_idname) == 0)
36290Sstevel@tonic-gate 				break;
36300Sstevel@tonic-gate 		}
36310Sstevel@tonic-gate 		releasestr(stp->sd_wrq);
36320Sstevel@tonic-gate 
36330Sstevel@tonic-gate 		*rvalp = (q ? 1 : 0);
36340Sstevel@tonic-gate 		return (error);
36350Sstevel@tonic-gate 	    }
36360Sstevel@tonic-gate 
36370Sstevel@tonic-gate 	case I_PUSH:
36380Sstevel@tonic-gate 	case __I_PUSH_NOCTTY:
36390Sstevel@tonic-gate 		/*
36400Sstevel@tonic-gate 		 * Push a module.
36410Sstevel@tonic-gate 		 * For the case __I_PUSH_NOCTTY push a module but
36420Sstevel@tonic-gate 		 * do not allocate controlling tty. See bugid 4025044
36430Sstevel@tonic-gate 		 */
36440Sstevel@tonic-gate 
36450Sstevel@tonic-gate 	    {
36460Sstevel@tonic-gate 		char mname[FMNAMESZ + 1];
36470Sstevel@tonic-gate 		fmodsw_impl_t *fp;
36480Sstevel@tonic-gate 		dev_t dummydev;
36490Sstevel@tonic-gate 
36500Sstevel@tonic-gate 		if (stp->sd_flag & STRHUP)
36510Sstevel@tonic-gate 			return (ENXIO);
36520Sstevel@tonic-gate 
36530Sstevel@tonic-gate 		/*
36540Sstevel@tonic-gate 		 * Get module name and look up in fmodsw.
36550Sstevel@tonic-gate 		 */
36560Sstevel@tonic-gate 		error = (copyflag & U_TO_K ? copyinstr : copystr)((void *)arg,
36570Sstevel@tonic-gate 		    mname, FMNAMESZ + 1, NULL);
36580Sstevel@tonic-gate 		if (error)
36590Sstevel@tonic-gate 			return ((error == ENAMETOOLONG) ? EINVAL : EFAULT);
36600Sstevel@tonic-gate 
36610Sstevel@tonic-gate 		if ((fp = fmodsw_find(mname, FMODSW_HOLD | FMODSW_LOAD)) ==
36620Sstevel@tonic-gate 		    NULL)
36630Sstevel@tonic-gate 			return (EINVAL);
36640Sstevel@tonic-gate 
36650Sstevel@tonic-gate 		TRACE_2(TR_FAC_STREAMS_FR, TR_I_PUSH,
36660Sstevel@tonic-gate 		    "I_PUSH:fp %p stp %p", fp, stp);
36670Sstevel@tonic-gate 
36680Sstevel@tonic-gate 		if (error = strstartplumb(stp, flag, cmd)) {
36690Sstevel@tonic-gate 			fmodsw_rele(fp);
36700Sstevel@tonic-gate 			return (error);
36710Sstevel@tonic-gate 		}
36720Sstevel@tonic-gate 
36730Sstevel@tonic-gate 		/*
36740Sstevel@tonic-gate 		 * See if any more modules can be pushed on this stream.
36750Sstevel@tonic-gate 		 * Note that this check must be done after strstartplumb()
36760Sstevel@tonic-gate 		 * since otherwise multiple threads issuing I_PUSHes on
36770Sstevel@tonic-gate 		 * the same stream will be able to exceed nstrpush.
36780Sstevel@tonic-gate 		 */
36790Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
36800Sstevel@tonic-gate 		if (stp->sd_pushcnt >= nstrpush) {
36810Sstevel@tonic-gate 			fmodsw_rele(fp);
36820Sstevel@tonic-gate 			strendplumb(stp);
36830Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
36840Sstevel@tonic-gate 			return (EINVAL);
36850Sstevel@tonic-gate 		}
36860Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
36870Sstevel@tonic-gate 
36880Sstevel@tonic-gate 		/*
36890Sstevel@tonic-gate 		 * Push new module and call its open routine
36900Sstevel@tonic-gate 		 * via qattach().  Modules don't change device
36910Sstevel@tonic-gate 		 * numbers, so just ignore dummydev here.
36920Sstevel@tonic-gate 		 */
36930Sstevel@tonic-gate 		dummydev = vp->v_rdev;
36940Sstevel@tonic-gate 		if ((error = qattach(rdq, &dummydev, 0, crp, fp,
36950Sstevel@tonic-gate 		    B_FALSE)) == 0) {
36960Sstevel@tonic-gate 			if (vp->v_type == VCHR && /* sorry, no pipes allowed */
36970Sstevel@tonic-gate 			    (cmd == I_PUSH) && (stp->sd_flag & STRISTTY)) {
36980Sstevel@tonic-gate 				/*
36990Sstevel@tonic-gate 				 * try to allocate it as a controlling terminal
37000Sstevel@tonic-gate 				 */
3701560Smeem 				stralloctty(stp);
37020Sstevel@tonic-gate 			}
37030Sstevel@tonic-gate 		}
37040Sstevel@tonic-gate 
37050Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
37060Sstevel@tonic-gate 
37070Sstevel@tonic-gate 		/*
37080Sstevel@tonic-gate 		 * As a performance concern we are caching the values of
37090Sstevel@tonic-gate 		 * q_minpsz and q_maxpsz of the module below the stream
37100Sstevel@tonic-gate 		 * head in the stream head.
37110Sstevel@tonic-gate 		 */
37120Sstevel@tonic-gate 		mutex_enter(QLOCK(stp->sd_wrq->q_next));
37130Sstevel@tonic-gate 		rmin = stp->sd_wrq->q_next->q_minpsz;
37140Sstevel@tonic-gate 		rmax = stp->sd_wrq->q_next->q_maxpsz;
37150Sstevel@tonic-gate 		mutex_exit(QLOCK(stp->sd_wrq->q_next));
37160Sstevel@tonic-gate 
37170Sstevel@tonic-gate 		/* Do this processing here as a performance concern */
37180Sstevel@tonic-gate 		if (strmsgsz != 0) {
37190Sstevel@tonic-gate 			if (rmax == INFPSZ)
37200Sstevel@tonic-gate 				rmax = strmsgsz;
37210Sstevel@tonic-gate 			else  {
37220Sstevel@tonic-gate 				if (vp->v_type == VFIFO)
37230Sstevel@tonic-gate 					rmax = MIN(PIPE_BUF, rmax);
37240Sstevel@tonic-gate 				else	rmax = MIN(strmsgsz, rmax);
37250Sstevel@tonic-gate 			}
37260Sstevel@tonic-gate 		}
37270Sstevel@tonic-gate 
37280Sstevel@tonic-gate 		mutex_enter(QLOCK(wrq));
37290Sstevel@tonic-gate 		stp->sd_qn_minpsz = rmin;
37300Sstevel@tonic-gate 		stp->sd_qn_maxpsz = rmax;
37310Sstevel@tonic-gate 		mutex_exit(QLOCK(wrq));
37320Sstevel@tonic-gate 
37330Sstevel@tonic-gate 		strendplumb(stp);
37340Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
37350Sstevel@tonic-gate 		return (error);
37360Sstevel@tonic-gate 	    }
37370Sstevel@tonic-gate 
37380Sstevel@tonic-gate 	case I_POP:
37390Sstevel@tonic-gate 	    {
37400Sstevel@tonic-gate 		queue_t	*q;
37410Sstevel@tonic-gate 
37420Sstevel@tonic-gate 		if (stp->sd_flag & STRHUP)
37430Sstevel@tonic-gate 			return (ENXIO);
37440Sstevel@tonic-gate 		if (!wrq->q_next)	/* for broken pipes */
37450Sstevel@tonic-gate 			return (EINVAL);
37460Sstevel@tonic-gate 
37470Sstevel@tonic-gate 		if (error = strstartplumb(stp, flag, cmd))
37480Sstevel@tonic-gate 			return (error);
37490Sstevel@tonic-gate 
37500Sstevel@tonic-gate 		/*
37510Sstevel@tonic-gate 		 * If there is an anchor on this stream and popping
37520Sstevel@tonic-gate 		 * the current module would attempt to pop through the
37530Sstevel@tonic-gate 		 * anchor, then disallow the pop unless we have sufficient
37540Sstevel@tonic-gate 		 * privileges; take the cheapest (non-locking) check
37550Sstevel@tonic-gate 		 * first.
37560Sstevel@tonic-gate 		 */
37570Sstevel@tonic-gate 		if (secpolicy_net_config(crp, B_TRUE) != 0) {
37580Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
37590Sstevel@tonic-gate 			/*
37600Sstevel@tonic-gate 			 * Anchors only apply if there's at least one
37610Sstevel@tonic-gate 			 * module on the stream (sd_pushcnt > 0).
37620Sstevel@tonic-gate 			 */
37630Sstevel@tonic-gate 			if (stp->sd_pushcnt > 0 &&
37640Sstevel@tonic-gate 			    stp->sd_pushcnt == stp->sd_anchor &&
37650Sstevel@tonic-gate 			    stp->sd_vnode->v_type != VFIFO) {
37660Sstevel@tonic-gate 				strendplumb(stp);
37670Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
37680Sstevel@tonic-gate 				/* Audit and report error */
37690Sstevel@tonic-gate 				return (secpolicy_net_config(crp, B_FALSE));
37700Sstevel@tonic-gate 			}
37710Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
37720Sstevel@tonic-gate 		}
37730Sstevel@tonic-gate 
37740Sstevel@tonic-gate 		q = wrq->q_next;
37750Sstevel@tonic-gate 		TRACE_2(TR_FAC_STREAMS_FR, TR_I_POP,
37760Sstevel@tonic-gate 			"I_POP:%p from %p", q, stp);
37770Sstevel@tonic-gate 		if (q->q_next == NULL || (q->q_flag & (QREADR|QISDRV))) {
37780Sstevel@tonic-gate 			error = EINVAL;
37790Sstevel@tonic-gate 		} else {
37800Sstevel@tonic-gate 			qdetach(_RD(q), 1, flag, crp, B_FALSE);
37810Sstevel@tonic-gate 			error = 0;
37820Sstevel@tonic-gate 		}
37830Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
37840Sstevel@tonic-gate 
37850Sstevel@tonic-gate 		/*
37860Sstevel@tonic-gate 		 * As a performance concern we are caching the values of
37870Sstevel@tonic-gate 		 * q_minpsz and q_maxpsz of the module below the stream
37880Sstevel@tonic-gate 		 * head in the stream head.
37890Sstevel@tonic-gate 		 */
37900Sstevel@tonic-gate 		mutex_enter(QLOCK(wrq->q_next));
37910Sstevel@tonic-gate 		rmin = wrq->q_next->q_minpsz;
37920Sstevel@tonic-gate 		rmax = wrq->q_next->q_maxpsz;
37930Sstevel@tonic-gate 		mutex_exit(QLOCK(wrq->q_next));
37940Sstevel@tonic-gate 
37950Sstevel@tonic-gate 		/* Do this processing here as a performance concern */
37960Sstevel@tonic-gate 		if (strmsgsz != 0) {
37970Sstevel@tonic-gate 			if (rmax == INFPSZ)
37980Sstevel@tonic-gate 				rmax = strmsgsz;
37990Sstevel@tonic-gate 			else  {
38000Sstevel@tonic-gate 				if (vp->v_type == VFIFO)
38010Sstevel@tonic-gate 					rmax = MIN(PIPE_BUF, rmax);
38020Sstevel@tonic-gate 				else	rmax = MIN(strmsgsz, rmax);
38030Sstevel@tonic-gate 			}
38040Sstevel@tonic-gate 		}
38050Sstevel@tonic-gate 
38060Sstevel@tonic-gate 		mutex_enter(QLOCK(wrq));
38070Sstevel@tonic-gate 		stp->sd_qn_minpsz = rmin;
38080Sstevel@tonic-gate 		stp->sd_qn_maxpsz = rmax;
38090Sstevel@tonic-gate 		mutex_exit(QLOCK(wrq));
38100Sstevel@tonic-gate 
38110Sstevel@tonic-gate 		/* If we popped through the anchor, then reset the anchor. */
38120Sstevel@tonic-gate 		if (stp->sd_pushcnt < stp->sd_anchor)
38130Sstevel@tonic-gate 			stp->sd_anchor = 0;
38140Sstevel@tonic-gate 
38150Sstevel@tonic-gate 		strendplumb(stp);
38160Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
38170Sstevel@tonic-gate 		return (error);
38180Sstevel@tonic-gate 	    }
38190Sstevel@tonic-gate 
38200Sstevel@tonic-gate 	case _I_MUXID2FD:
38210Sstevel@tonic-gate 	{
38220Sstevel@tonic-gate 		/*
38230Sstevel@tonic-gate 		 * Create a fd for a I_PLINK'ed lower stream with a given
38240Sstevel@tonic-gate 		 * muxid.  With the fd, application can send down ioctls,
38250Sstevel@tonic-gate 		 * like I_LIST, to the previously I_PLINK'ed stream.  Note
38260Sstevel@tonic-gate 		 * that after getting the fd, the application has to do an
38270Sstevel@tonic-gate 		 * I_PUNLINK on the muxid before it can do any operation
38280Sstevel@tonic-gate 		 * on the lower stream.  This is required by spec1170.
38290Sstevel@tonic-gate 		 *
38300Sstevel@tonic-gate 		 * The fd used to do this ioctl should point to the same
38310Sstevel@tonic-gate 		 * controlling device used to do the I_PLINK.  If it uses
38320Sstevel@tonic-gate 		 * a different stream or an invalid muxid, I_MUXID2FD will
38330Sstevel@tonic-gate 		 * fail.  The error code is set to EINVAL.
38340Sstevel@tonic-gate 		 *
38350Sstevel@tonic-gate 		 * The intended use of this interface is the following.
38360Sstevel@tonic-gate 		 * An application I_PLINK'ed a stream and exits.  The fd
38370Sstevel@tonic-gate 		 * to the lower stream is gone.  Another application
38380Sstevel@tonic-gate 		 * wants to get a fd to the lower stream, it uses I_MUXID2FD.
38390Sstevel@tonic-gate 		 */
38400Sstevel@tonic-gate 		int muxid = (int)arg;
38410Sstevel@tonic-gate 		int fd;
38420Sstevel@tonic-gate 		linkinfo_t *linkp;
38430Sstevel@tonic-gate 		struct file *fp;
38440Sstevel@tonic-gate 
38450Sstevel@tonic-gate 		/*
38460Sstevel@tonic-gate 		 * Do not allow the wildcard muxid.  This ioctl is not
38470Sstevel@tonic-gate 		 * intended to find arbitrary link.
38480Sstevel@tonic-gate 		 */
38490Sstevel@tonic-gate 		if (muxid == 0) {
38500Sstevel@tonic-gate 			return (EINVAL);
38510Sstevel@tonic-gate 		}
38520Sstevel@tonic-gate 
38530Sstevel@tonic-gate 		mutex_enter(&muxifier);
38540Sstevel@tonic-gate 		linkp = findlinks(vp->v_stream, muxid, LINKPERSIST);
38550Sstevel@tonic-gate 		if (linkp == NULL) {
38560Sstevel@tonic-gate 			mutex_exit(&muxifier);
38570Sstevel@tonic-gate 			return (EINVAL);
38580Sstevel@tonic-gate 		}
38590Sstevel@tonic-gate 
38600Sstevel@tonic-gate 		if ((fd = ufalloc(0)) == -1) {
38610Sstevel@tonic-gate 			mutex_exit(&muxifier);
38620Sstevel@tonic-gate 			return (EMFILE);
38630Sstevel@tonic-gate 		}
38640Sstevel@tonic-gate 		fp = linkp->li_fpdown;
38650Sstevel@tonic-gate 		mutex_enter(&fp->f_tlock);
38660Sstevel@tonic-gate 		fp->f_count++;
38670Sstevel@tonic-gate 		mutex_exit(&fp->f_tlock);
38680Sstevel@tonic-gate 		mutex_exit(&muxifier);
38690Sstevel@tonic-gate 		setf(fd, fp);
38700Sstevel@tonic-gate 		*rvalp = fd;
38710Sstevel@tonic-gate 		return (0);
38720Sstevel@tonic-gate 	}
38730Sstevel@tonic-gate 
38740Sstevel@tonic-gate 	case _I_INSERT:
38750Sstevel@tonic-gate 	{
38760Sstevel@tonic-gate 		/*
38770Sstevel@tonic-gate 		 * To insert a module to a given position in a stream.
38780Sstevel@tonic-gate 		 * In the first release, only allow privileged user
38790Sstevel@tonic-gate 		 * to use this ioctl.
38800Sstevel@tonic-gate 		 *
38810Sstevel@tonic-gate 		 * Note that we do not plan to support this ioctl
38820Sstevel@tonic-gate 		 * on pipes in the first release.  We want to learn more
38830Sstevel@tonic-gate 		 * about the implications of these ioctls before extending
38840Sstevel@tonic-gate 		 * their support.  And we do not think these features are
38850Sstevel@tonic-gate 		 * valuable for pipes.
38860Sstevel@tonic-gate 		 *
38870Sstevel@tonic-gate 		 * Neither do we support O/C hot stream.  Note that only
38880Sstevel@tonic-gate 		 * the upper streams of TCP/IP stack are O/C hot streams.
38890Sstevel@tonic-gate 		 * The lower IP stream is not.
38900Sstevel@tonic-gate 		 * When there is a O/C cold barrier, we only allow inserts
38910Sstevel@tonic-gate 		 * above the barrier.
38920Sstevel@tonic-gate 		 */
38930Sstevel@tonic-gate 		STRUCT_DECL(strmodconf, strmodinsert);
38940Sstevel@tonic-gate 		char mod_name[FMNAMESZ + 1];
38950Sstevel@tonic-gate 		fmodsw_impl_t *fp;
38960Sstevel@tonic-gate 		dev_t dummydev;
38970Sstevel@tonic-gate 		queue_t *tmp_wrq;
38980Sstevel@tonic-gate 		int pos;
38990Sstevel@tonic-gate 		boolean_t is_insert;
39000Sstevel@tonic-gate 
39010Sstevel@tonic-gate 		STRUCT_INIT(strmodinsert, flag);
39020Sstevel@tonic-gate 		if (stp->sd_flag & STRHUP)
39030Sstevel@tonic-gate 			return (ENXIO);
39040Sstevel@tonic-gate 		if (STRMATED(stp))
39050Sstevel@tonic-gate 			return (EINVAL);
39060Sstevel@tonic-gate 		if ((error = secpolicy_net_config(crp, B_FALSE)) != 0)
39070Sstevel@tonic-gate 			return (error);
39080Sstevel@tonic-gate 
39090Sstevel@tonic-gate 		error = strcopyin((void *)arg, STRUCT_BUF(strmodinsert),
39100Sstevel@tonic-gate 		    STRUCT_SIZE(strmodinsert), copyflag);
39110Sstevel@tonic-gate 		if (error)
39120Sstevel@tonic-gate 			return (error);
39130Sstevel@tonic-gate 
39140Sstevel@tonic-gate 		/*
39150Sstevel@tonic-gate 		 * Get module name and look up in fmodsw.
39160Sstevel@tonic-gate 		 */
39170Sstevel@tonic-gate 		error = (copyflag & U_TO_K ? copyinstr :
39180Sstevel@tonic-gate 		    copystr)(STRUCT_FGETP(strmodinsert, mod_name),
39190Sstevel@tonic-gate 		    mod_name, FMNAMESZ + 1, NULL);
39200Sstevel@tonic-gate 		if (error)
39210Sstevel@tonic-gate 			return ((error == ENAMETOOLONG) ? EINVAL : EFAULT);
39220Sstevel@tonic-gate 
39230Sstevel@tonic-gate 		if ((fp = fmodsw_find(mod_name, FMODSW_HOLD | FMODSW_LOAD)) ==
39240Sstevel@tonic-gate 		    NULL)
39250Sstevel@tonic-gate 			return (EINVAL);
39260Sstevel@tonic-gate 
39270Sstevel@tonic-gate 		if (error = strstartplumb(stp, flag, cmd)) {
39280Sstevel@tonic-gate 			fmodsw_rele(fp);
39290Sstevel@tonic-gate 			return (error);
39300Sstevel@tonic-gate 		}
39310Sstevel@tonic-gate 
39320Sstevel@tonic-gate 		/*
39330Sstevel@tonic-gate 		 * Is this _I_INSERT just like an I_PUSH?  We need to know
39340Sstevel@tonic-gate 		 * this because we do some optimizations if this is a
39350Sstevel@tonic-gate 		 * module being pushed.
39360Sstevel@tonic-gate 		 */
39370Sstevel@tonic-gate 		pos = STRUCT_FGET(strmodinsert, pos);
39380Sstevel@tonic-gate 		is_insert = (pos != 0);
39390Sstevel@tonic-gate 
39400Sstevel@tonic-gate 		/*
39410Sstevel@tonic-gate 		 * Make sure pos is valid.  Even though it is not an I_PUSH,
39420Sstevel@tonic-gate 		 * we impose the same limit on the number of modules in a
39430Sstevel@tonic-gate 		 * stream.
39440Sstevel@tonic-gate 		 */
39450Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
39460Sstevel@tonic-gate 		if (stp->sd_pushcnt >= nstrpush || pos < 0 ||
39470Sstevel@tonic-gate 		    pos > stp->sd_pushcnt) {
39480Sstevel@tonic-gate 			fmodsw_rele(fp);
39490Sstevel@tonic-gate 			strendplumb(stp);
39500Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
39510Sstevel@tonic-gate 			return (EINVAL);
39520Sstevel@tonic-gate 		}
39530Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
39540Sstevel@tonic-gate 
39550Sstevel@tonic-gate 		/*
39560Sstevel@tonic-gate 		 * First find the correct position this module to
39570Sstevel@tonic-gate 		 * be inserted.  We don't need to call claimstr()
39580Sstevel@tonic-gate 		 * as the stream should not be changing at this point.
39590Sstevel@tonic-gate 		 *
39600Sstevel@tonic-gate 		 * Insert new module and call its open routine
39610Sstevel@tonic-gate 		 * via qattach().  Modules don't change device
39620Sstevel@tonic-gate 		 * numbers, so just ignore dummydev here.
39630Sstevel@tonic-gate 		 */
39640Sstevel@tonic-gate 		for (tmp_wrq = stp->sd_wrq; pos > 0;
39650Sstevel@tonic-gate 		    tmp_wrq = tmp_wrq->q_next, pos--) {
39660Sstevel@tonic-gate 			ASSERT(SAMESTR(tmp_wrq));
39670Sstevel@tonic-gate 		}
39680Sstevel@tonic-gate 		dummydev = vp->v_rdev;
39690Sstevel@tonic-gate 		if ((error = qattach(_RD(tmp_wrq), &dummydev, 0, crp,
39700Sstevel@tonic-gate 		    fp, is_insert)) != 0) {
39710Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
39720Sstevel@tonic-gate 			strendplumb(stp);
39730Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
39740Sstevel@tonic-gate 			return (error);
39750Sstevel@tonic-gate 		}
39760Sstevel@tonic-gate 
39770Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
39780Sstevel@tonic-gate 
39790Sstevel@tonic-gate 		/*
39800Sstevel@tonic-gate 		 * As a performance concern we are caching the values of
39810Sstevel@tonic-gate 		 * q_minpsz and q_maxpsz of the module below the stream
39820Sstevel@tonic-gate 		 * head in the stream head.
39830Sstevel@tonic-gate 		 */
39840Sstevel@tonic-gate 		if (!is_insert) {
39850Sstevel@tonic-gate 			mutex_enter(QLOCK(stp->sd_wrq->q_next));
39860Sstevel@tonic-gate 			rmin = stp->sd_wrq->q_next->q_minpsz;
39870Sstevel@tonic-gate 			rmax = stp->sd_wrq->q_next->q_maxpsz;
39880Sstevel@tonic-gate 			mutex_exit(QLOCK(stp->sd_wrq->q_next));
39890Sstevel@tonic-gate 
39900Sstevel@tonic-gate 			/* Do this processing here as a performance concern */
39910Sstevel@tonic-gate 			if (strmsgsz != 0) {
39920Sstevel@tonic-gate 				if (rmax == INFPSZ) {
39930Sstevel@tonic-gate 					rmax = strmsgsz;
39940Sstevel@tonic-gate 				} else  {
39950Sstevel@tonic-gate 					rmax = MIN(strmsgsz, rmax);
39960Sstevel@tonic-gate 				}
39970Sstevel@tonic-gate 			}
39980Sstevel@tonic-gate 
39990Sstevel@tonic-gate 			mutex_enter(QLOCK(wrq));
40000Sstevel@tonic-gate 			stp->sd_qn_minpsz = rmin;
40010Sstevel@tonic-gate 			stp->sd_qn_maxpsz = rmax;
40020Sstevel@tonic-gate 			mutex_exit(QLOCK(wrq));
40030Sstevel@tonic-gate 		}
40040Sstevel@tonic-gate 
40050Sstevel@tonic-gate 		/*
40060Sstevel@tonic-gate 		 * Need to update the anchor value if this module is
40070Sstevel@tonic-gate 		 * inserted below the anchor point.
40080Sstevel@tonic-gate 		 */
40090Sstevel@tonic-gate 		if (stp->sd_anchor != 0) {
40100Sstevel@tonic-gate 			pos = STRUCT_FGET(strmodinsert, pos);
40110Sstevel@tonic-gate 			if (pos >= (stp->sd_pushcnt - stp->sd_anchor))
40120Sstevel@tonic-gate 				stp->sd_anchor++;
40130Sstevel@tonic-gate 		}
40140Sstevel@tonic-gate 
40150Sstevel@tonic-gate 		strendplumb(stp);
40160Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
40170Sstevel@tonic-gate 		return (0);
40180Sstevel@tonic-gate 	}
40190Sstevel@tonic-gate 
40200Sstevel@tonic-gate 	case _I_REMOVE:
40210Sstevel@tonic-gate 	{
40220Sstevel@tonic-gate 		/*
40230Sstevel@tonic-gate 		 * To remove a module with a given name in a stream.  The
40240Sstevel@tonic-gate 		 * caller of this ioctl needs to provide both the name and
40250Sstevel@tonic-gate 		 * the position of the module to be removed.  This eliminates
40260Sstevel@tonic-gate 		 * the ambiguity of removal if a module is inserted/pushed
40270Sstevel@tonic-gate 		 * multiple times in a stream.  In the first release, only
40280Sstevel@tonic-gate 		 * allow privileged user to use this ioctl.
40290Sstevel@tonic-gate 		 *
40300Sstevel@tonic-gate 		 * Note that we do not plan to support this ioctl
40310Sstevel@tonic-gate 		 * on pipes in the first release.  We want to learn more
40320Sstevel@tonic-gate 		 * about the implications of these ioctls before extending
40330Sstevel@tonic-gate 		 * their support.  And we do not think these features are
40340Sstevel@tonic-gate 		 * valuable for pipes.
40350Sstevel@tonic-gate 		 *
40360Sstevel@tonic-gate 		 * Neither do we support O/C hot stream.  Note that only
40370Sstevel@tonic-gate 		 * the upper streams of TCP/IP stack are O/C hot streams.
40380Sstevel@tonic-gate 		 * The lower IP stream is not.
40390Sstevel@tonic-gate 		 * When there is a O/C cold barrier we do not allow removal
40400Sstevel@tonic-gate 		 * below the barrier.
40410Sstevel@tonic-gate 		 *
40420Sstevel@tonic-gate 		 * Also note that _I_REMOVE cannot be used to remove a
40430Sstevel@tonic-gate 		 * driver or the stream head.
40440Sstevel@tonic-gate 		 */
40450Sstevel@tonic-gate 		STRUCT_DECL(strmodconf, strmodremove);
40460Sstevel@tonic-gate 		queue_t	*q;
40470Sstevel@tonic-gate 		int pos;
40480Sstevel@tonic-gate 		char mod_name[FMNAMESZ + 1];
40490Sstevel@tonic-gate 		boolean_t is_remove;
40500Sstevel@tonic-gate 
40510Sstevel@tonic-gate 		STRUCT_INIT(strmodremove, flag);
40520Sstevel@tonic-gate 		if (stp->sd_flag & STRHUP)
40530Sstevel@tonic-gate 			return (ENXIO);
40540Sstevel@tonic-gate 		if (STRMATED(stp))
40550Sstevel@tonic-gate 			return (EINVAL);
40560Sstevel@tonic-gate 		if ((error = secpolicy_net_config(crp, B_FALSE)) != 0)
40570Sstevel@tonic-gate 			return (error);
40580Sstevel@tonic-gate 
40590Sstevel@tonic-gate 		error = strcopyin((void *)arg, STRUCT_BUF(strmodremove),
40600Sstevel@tonic-gate 		    STRUCT_SIZE(strmodremove), copyflag);
40610Sstevel@tonic-gate 		if (error)
40620Sstevel@tonic-gate 			return (error);
40630Sstevel@tonic-gate 
40640Sstevel@tonic-gate 		error = (copyflag & U_TO_K ? copyinstr :
40650Sstevel@tonic-gate 		    copystr)(STRUCT_FGETP(strmodremove, mod_name),
40660Sstevel@tonic-gate 		    mod_name, FMNAMESZ + 1, NULL);
40670Sstevel@tonic-gate 		if (error)
40680Sstevel@tonic-gate 			return ((error == ENAMETOOLONG) ? EINVAL : EFAULT);
40690Sstevel@tonic-gate 
40700Sstevel@tonic-gate 		if ((error = strstartplumb(stp, flag, cmd)) != 0)
40710Sstevel@tonic-gate 			return (error);
40720Sstevel@tonic-gate 
40730Sstevel@tonic-gate 		/*
40740Sstevel@tonic-gate 		 * Match the name of given module to the name of module at
40750Sstevel@tonic-gate 		 * the given position.
40760Sstevel@tonic-gate 		 */
40770Sstevel@tonic-gate 		pos = STRUCT_FGET(strmodremove, pos);
40780Sstevel@tonic-gate 
40790Sstevel@tonic-gate 		is_remove = (pos != 0);
40800Sstevel@tonic-gate 		for (q = stp->sd_wrq->q_next; SAMESTR(q) && pos > 0;
40810Sstevel@tonic-gate 		    q = q->q_next, pos--)
40820Sstevel@tonic-gate 			;
40830Sstevel@tonic-gate 		if (pos > 0 || ! SAMESTR(q) ||
40840Sstevel@tonic-gate 		    strncmp(q->q_qinfo->qi_minfo->mi_idname, mod_name,
40850Sstevel@tonic-gate 		    strlen(q->q_qinfo->qi_minfo->mi_idname)) != 0) {
40860Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
40870Sstevel@tonic-gate 			strendplumb(stp);
40880Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
40890Sstevel@tonic-gate 			return (EINVAL);
40900Sstevel@tonic-gate 		}
40910Sstevel@tonic-gate 
40920Sstevel@tonic-gate 		ASSERT(!(q->q_flag & QREADR));
40930Sstevel@tonic-gate 		qdetach(_RD(q), 1, flag, crp, is_remove);
40940Sstevel@tonic-gate 
40950Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
40960Sstevel@tonic-gate 
40970Sstevel@tonic-gate 		/*
40980Sstevel@tonic-gate 		 * As a performance concern we are caching the values of
40990Sstevel@tonic-gate 		 * q_minpsz and q_maxpsz of the module below the stream
41000Sstevel@tonic-gate 		 * head in the stream head.
41010Sstevel@tonic-gate 		 */
41020Sstevel@tonic-gate 		if (!is_remove) {
41030Sstevel@tonic-gate 			mutex_enter(QLOCK(wrq->q_next));
41040Sstevel@tonic-gate 			rmin = wrq->q_next->q_minpsz;
41050Sstevel@tonic-gate 			rmax = wrq->q_next->q_maxpsz;
41060Sstevel@tonic-gate 			mutex_exit(QLOCK(wrq->q_next));
41070Sstevel@tonic-gate 
41080Sstevel@tonic-gate 			/* Do this processing here as a performance concern */
41090Sstevel@tonic-gate 			if (strmsgsz != 0) {
41100Sstevel@tonic-gate 				if (rmax == INFPSZ)
41110Sstevel@tonic-gate 					rmax = strmsgsz;
41120Sstevel@tonic-gate 				else  {
41130Sstevel@tonic-gate 					if (vp->v_type == VFIFO)
41140Sstevel@tonic-gate 						rmax = MIN(PIPE_BUF, rmax);
41150Sstevel@tonic-gate 					else	rmax = MIN(strmsgsz, rmax);
41160Sstevel@tonic-gate 				}
41170Sstevel@tonic-gate 			}
41180Sstevel@tonic-gate 
41190Sstevel@tonic-gate 			mutex_enter(QLOCK(wrq));
41200Sstevel@tonic-gate 			stp->sd_qn_minpsz = rmin;
41210Sstevel@tonic-gate 			stp->sd_qn_maxpsz = rmax;
41220Sstevel@tonic-gate 			mutex_exit(QLOCK(wrq));
41230Sstevel@tonic-gate 		}
41240Sstevel@tonic-gate 
41250Sstevel@tonic-gate 		/*
41260Sstevel@tonic-gate 		 * Need to update the anchor value if this module is removed
41270Sstevel@tonic-gate 		 * at or below the anchor point.  If the removed module is at
41280Sstevel@tonic-gate 		 * the anchor point, remove the anchor for this stream if
41290Sstevel@tonic-gate 		 * there is no module above the anchor point.  Otherwise, if
41300Sstevel@tonic-gate 		 * the removed module is below the anchor point, decrement the
41310Sstevel@tonic-gate 		 * anchor point by 1.
41320Sstevel@tonic-gate 		 */
41330Sstevel@tonic-gate 		if (stp->sd_anchor != 0) {
41340Sstevel@tonic-gate 			pos = STRUCT_FGET(strmodremove, pos);
41350Sstevel@tonic-gate 			if (pos == 0)
41360Sstevel@tonic-gate 				stp->sd_anchor = 0;
41370Sstevel@tonic-gate 			else if (pos > (stp->sd_pushcnt - stp->sd_anchor + 1))
41380Sstevel@tonic-gate 				stp->sd_anchor--;
41390Sstevel@tonic-gate 		}
41400Sstevel@tonic-gate 
41410Sstevel@tonic-gate 		strendplumb(stp);
41420Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
41430Sstevel@tonic-gate 		return (0);
41440Sstevel@tonic-gate 	}
41450Sstevel@tonic-gate 
41460Sstevel@tonic-gate 	case I_ANCHOR:
41470Sstevel@tonic-gate 		/*
41480Sstevel@tonic-gate 		 * Set the anchor position on the stream to reside at
41490Sstevel@tonic-gate 		 * the top module (in other words, the top module
41500Sstevel@tonic-gate 		 * cannot be popped).  Anchors with a FIFO make no
41510Sstevel@tonic-gate 		 * obvious sense, so they're not allowed.
41520Sstevel@tonic-gate 		 */
41530Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
41540Sstevel@tonic-gate 
41550Sstevel@tonic-gate 		if (stp->sd_vnode->v_type == VFIFO) {
41560Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
41570Sstevel@tonic-gate 			return (EINVAL);
41580Sstevel@tonic-gate 		}
41590Sstevel@tonic-gate 
41600Sstevel@tonic-gate 		stp->sd_anchor = stp->sd_pushcnt;
41610Sstevel@tonic-gate 
41620Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
41630Sstevel@tonic-gate 		return (0);
41640Sstevel@tonic-gate 
41650Sstevel@tonic-gate 	case I_LOOK:
41660Sstevel@tonic-gate 		/*
41670Sstevel@tonic-gate 		 * Get name of first module downstream.
41680Sstevel@tonic-gate 		 * If no module, return an error.
41690Sstevel@tonic-gate 		 */
41700Sstevel@tonic-gate 	    {
41710Sstevel@tonic-gate 		claimstr(wrq);
41720Sstevel@tonic-gate 		if (_SAMESTR(wrq) && wrq->q_next->q_next) {
41730Sstevel@tonic-gate 			char *name = wrq->q_next->q_qinfo->qi_minfo->mi_idname;
41740Sstevel@tonic-gate 			error = strcopyout(name, (void *)arg, strlen(name) + 1,
41750Sstevel@tonic-gate 			    copyflag);
41760Sstevel@tonic-gate 			releasestr(wrq);
41770Sstevel@tonic-gate 			return (error);
41780Sstevel@tonic-gate 		}
41790Sstevel@tonic-gate 		releasestr(wrq);
41800Sstevel@tonic-gate 		return (EINVAL);
41810Sstevel@tonic-gate 	    }
41820Sstevel@tonic-gate 
41830Sstevel@tonic-gate 	case I_LINK:
41840Sstevel@tonic-gate 	case I_PLINK:
41850Sstevel@tonic-gate 		/*
41860Sstevel@tonic-gate 		 * Link a multiplexor.
41870Sstevel@tonic-gate 		 */
41880Sstevel@tonic-gate 		return (mlink(vp, cmd, (int)arg, crp, rvalp, 0));
41890Sstevel@tonic-gate 
41900Sstevel@tonic-gate 	case _I_PLINK_LH:
41910Sstevel@tonic-gate 		/*
41920Sstevel@tonic-gate 		 * Link a multiplexor: Call must originate from kernel.
41930Sstevel@tonic-gate 		 */
41940Sstevel@tonic-gate 		if (kioctl)
41950Sstevel@tonic-gate 			return (ldi_mlink_lh(vp, cmd, arg, crp, rvalp));
41960Sstevel@tonic-gate 
41970Sstevel@tonic-gate 		return (EINVAL);
41980Sstevel@tonic-gate 	case I_UNLINK:
41990Sstevel@tonic-gate 	case I_PUNLINK:
42000Sstevel@tonic-gate 		/*
42010Sstevel@tonic-gate 		 * Unlink a multiplexor.
42020Sstevel@tonic-gate 		 * If arg is -1, unlink all links for which this is the
42030Sstevel@tonic-gate 		 * controlling stream.  Otherwise, arg is an index number
42040Sstevel@tonic-gate 		 * for a link to be removed.
42050Sstevel@tonic-gate 		 */
42060Sstevel@tonic-gate 	    {
42070Sstevel@tonic-gate 		struct linkinfo *linkp;
42080Sstevel@tonic-gate 		int native_arg = (int)arg;
42090Sstevel@tonic-gate 		int type;
42100Sstevel@tonic-gate 
42110Sstevel@tonic-gate 		TRACE_1(TR_FAC_STREAMS_FR,
42120Sstevel@tonic-gate 			TR_I_UNLINK, "I_UNLINK/I_PUNLINK:%p", stp);
42130Sstevel@tonic-gate 		if (vp->v_type == VFIFO) {
42140Sstevel@tonic-gate 			return (EINVAL);
42150Sstevel@tonic-gate 		}
42160Sstevel@tonic-gate 		if (cmd == I_UNLINK)
42170Sstevel@tonic-gate 			type = LINKNORMAL;
42180Sstevel@tonic-gate 		else	/* I_PUNLINK */
42190Sstevel@tonic-gate 			type = LINKPERSIST;
42200Sstevel@tonic-gate 		if (native_arg == 0) {
42210Sstevel@tonic-gate 			return (EINVAL);
42220Sstevel@tonic-gate 		}
42230Sstevel@tonic-gate 		if (native_arg == MUXID_ALL)
42240Sstevel@tonic-gate 			error = munlinkall(stp, type, crp, rvalp);
42250Sstevel@tonic-gate 		else {
42260Sstevel@tonic-gate 			mutex_enter(&muxifier);
42270Sstevel@tonic-gate 			if (!(linkp = findlinks(stp, (int)arg, type))) {
42280Sstevel@tonic-gate 				/* invalid user supplied index number */
42290Sstevel@tonic-gate 				mutex_exit(&muxifier);
42300Sstevel@tonic-gate 				return (EINVAL);
42310Sstevel@tonic-gate 			}
42320Sstevel@tonic-gate 			/* munlink drops the muxifier lock */
42330Sstevel@tonic-gate 			error = munlink(stp, linkp, type, crp, rvalp);
42340Sstevel@tonic-gate 		}
42350Sstevel@tonic-gate 		return (error);
42360Sstevel@tonic-gate 	    }
42370Sstevel@tonic-gate 
42380Sstevel@tonic-gate 	case I_FLUSH:
42390Sstevel@tonic-gate 		/*
42400Sstevel@tonic-gate 		 * send a flush message downstream
42410Sstevel@tonic-gate 		 * flush message can indicate
42420Sstevel@tonic-gate 		 * FLUSHR - flush read queue
42430Sstevel@tonic-gate 		 * FLUSHW - flush write queue
42440Sstevel@tonic-gate 		 * FLUSHRW - flush read/write queue
42450Sstevel@tonic-gate 		 */
42460Sstevel@tonic-gate 		if (stp->sd_flag & STRHUP)
42470Sstevel@tonic-gate 			return (ENXIO);
42480Sstevel@tonic-gate 		if (arg & ~FLUSHRW)
42490Sstevel@tonic-gate 			return (EINVAL);
42500Sstevel@tonic-gate 
42510Sstevel@tonic-gate 		for (;;) {
42520Sstevel@tonic-gate 			if (putnextctl1(stp->sd_wrq, M_FLUSH, (int)arg)) {
42530Sstevel@tonic-gate 				break;
42540Sstevel@tonic-gate 			}
42550Sstevel@tonic-gate 			if (error = strwaitbuf(1, BPRI_HI)) {
42560Sstevel@tonic-gate 				return (error);
42570Sstevel@tonic-gate 			}
42580Sstevel@tonic-gate 		}
42590Sstevel@tonic-gate 
42600Sstevel@tonic-gate 		/*
42610Sstevel@tonic-gate 		 * Send down an unsupported ioctl and wait for the nack
42620Sstevel@tonic-gate 		 * in order to allow the M_FLUSH to propagate back
42630Sstevel@tonic-gate 		 * up to the stream head.
42640Sstevel@tonic-gate 		 * Replaces if (qready()) runqueues();
42650Sstevel@tonic-gate 		 */
42660Sstevel@tonic-gate 		strioc.ic_cmd = -1;	/* The unsupported ioctl */
42670Sstevel@tonic-gate 		strioc.ic_timout = 0;
42680Sstevel@tonic-gate 		strioc.ic_len = 0;
42690Sstevel@tonic-gate 		strioc.ic_dp = NULL;
42700Sstevel@tonic-gate 		(void) strdoioctl(stp, &strioc, flag, K_TO_K, crp, rvalp);
42710Sstevel@tonic-gate 		*rvalp = 0;
42720Sstevel@tonic-gate 		return (0);
42730Sstevel@tonic-gate 
42740Sstevel@tonic-gate 	case I_FLUSHBAND:
42750Sstevel@tonic-gate 	    {
42760Sstevel@tonic-gate 		struct bandinfo binfo;
42770Sstevel@tonic-gate 
42780Sstevel@tonic-gate 		error = strcopyin((void *)arg, &binfo, sizeof (binfo),
42790Sstevel@tonic-gate 		    copyflag);
42800Sstevel@tonic-gate 		if (error)
42810Sstevel@tonic-gate 			return (error);
42820Sstevel@tonic-gate 		if (stp->sd_flag & STRHUP)
42830Sstevel@tonic-gate 			return (ENXIO);
42840Sstevel@tonic-gate 		if (binfo.bi_flag & ~FLUSHRW)
42850Sstevel@tonic-gate 			return (EINVAL);
42860Sstevel@tonic-gate 		while (!(mp = allocb(2, BPRI_HI))) {
42870Sstevel@tonic-gate 			if (error = strwaitbuf(2, BPRI_HI))
42880Sstevel@tonic-gate 				return (error);
42890Sstevel@tonic-gate 		}
42900Sstevel@tonic-gate 		mp->b_datap->db_type = M_FLUSH;
42910Sstevel@tonic-gate 		*mp->b_wptr++ = binfo.bi_flag | FLUSHBAND;
42920Sstevel@tonic-gate 		*mp->b_wptr++ = binfo.bi_pri;
42930Sstevel@tonic-gate 		putnext(stp->sd_wrq, mp);
42940Sstevel@tonic-gate 		/*
42950Sstevel@tonic-gate 		 * Send down an unsupported ioctl and wait for the nack
42960Sstevel@tonic-gate 		 * in order to allow the M_FLUSH to propagate back
42970Sstevel@tonic-gate 		 * up to the stream head.
42980Sstevel@tonic-gate 		 * Replaces if (qready()) runqueues();
42990Sstevel@tonic-gate 		 */
43000Sstevel@tonic-gate 		strioc.ic_cmd = -1;	/* The unsupported ioctl */
43010Sstevel@tonic-gate 		strioc.ic_timout = 0;
43020Sstevel@tonic-gate 		strioc.ic_len = 0;
43030Sstevel@tonic-gate 		strioc.ic_dp = NULL;
43040Sstevel@tonic-gate 		(void) strdoioctl(stp, &strioc, flag, K_TO_K, crp, rvalp);
43050Sstevel@tonic-gate 		*rvalp = 0;
43060Sstevel@tonic-gate 		return (0);
43070Sstevel@tonic-gate 	    }
43080Sstevel@tonic-gate 
43090Sstevel@tonic-gate 	case I_SRDOPT:
43100Sstevel@tonic-gate 		/*
43110Sstevel@tonic-gate 		 * Set read options
43120Sstevel@tonic-gate 		 *
43130Sstevel@tonic-gate 		 * RNORM - default stream mode
43140Sstevel@tonic-gate 		 * RMSGN - message no discard
43150Sstevel@tonic-gate 		 * RMSGD - message discard
43160Sstevel@tonic-gate 		 * RPROTNORM - fail read with EBADMSG for M_[PC]PROTOs
43170Sstevel@tonic-gate 		 * RPROTDAT - convert M_[PC]PROTOs to M_DATAs
43180Sstevel@tonic-gate 		 * RPROTDIS - discard M_[PC]PROTOs and retain M_DATAs
43190Sstevel@tonic-gate 		 */
43200Sstevel@tonic-gate 		if (arg & ~(RMODEMASK | RPROTMASK))
43210Sstevel@tonic-gate 			return (EINVAL);
43220Sstevel@tonic-gate 
43230Sstevel@tonic-gate 		if ((arg & (RMSGD|RMSGN)) == (RMSGD|RMSGN))
43240Sstevel@tonic-gate 			return (EINVAL);
43250Sstevel@tonic-gate 
43260Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
43270Sstevel@tonic-gate 		switch (arg & RMODEMASK) {
43280Sstevel@tonic-gate 		case RNORM:
43290Sstevel@tonic-gate 			stp->sd_read_opt &= ~(RD_MSGDIS | RD_MSGNODIS);
43300Sstevel@tonic-gate 			break;
43310Sstevel@tonic-gate 		case RMSGD:
43320Sstevel@tonic-gate 			stp->sd_read_opt = (stp->sd_read_opt & ~RD_MSGNODIS) |
43330Sstevel@tonic-gate 			    RD_MSGDIS;
43340Sstevel@tonic-gate 			break;
43350Sstevel@tonic-gate 		case RMSGN:
43360Sstevel@tonic-gate 			stp->sd_read_opt = (stp->sd_read_opt & ~RD_MSGDIS) |
43370Sstevel@tonic-gate 			    RD_MSGNODIS;
43380Sstevel@tonic-gate 			break;
43390Sstevel@tonic-gate 		}
43400Sstevel@tonic-gate 
43410Sstevel@tonic-gate 		switch (arg & RPROTMASK) {
43420Sstevel@tonic-gate 		case RPROTNORM:
43430Sstevel@tonic-gate 			stp->sd_read_opt &= ~(RD_PROTDAT | RD_PROTDIS);
43440Sstevel@tonic-gate 			break;
43450Sstevel@tonic-gate 
43460Sstevel@tonic-gate 		case RPROTDAT:
43470Sstevel@tonic-gate 			stp->sd_read_opt = ((stp->sd_read_opt & ~RD_PROTDIS) |
43480Sstevel@tonic-gate 			    RD_PROTDAT);
43490Sstevel@tonic-gate 			break;
43500Sstevel@tonic-gate 
43510Sstevel@tonic-gate 		case RPROTDIS:
43520Sstevel@tonic-gate 			stp->sd_read_opt = ((stp->sd_read_opt & ~RD_PROTDAT) |
43530Sstevel@tonic-gate 			    RD_PROTDIS);
43540Sstevel@tonic-gate 			break;
43550Sstevel@tonic-gate 		}
43560Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
43570Sstevel@tonic-gate 		return (0);
43580Sstevel@tonic-gate 
43590Sstevel@tonic-gate 	case I_GRDOPT:
43600Sstevel@tonic-gate 		/*
43610Sstevel@tonic-gate 		 * Get read option and return the value
43620Sstevel@tonic-gate 		 * to spot pointed to by arg
43630Sstevel@tonic-gate 		 */
43640Sstevel@tonic-gate 	    {
43650Sstevel@tonic-gate 		int rdopt;
43660Sstevel@tonic-gate 
43670Sstevel@tonic-gate 		rdopt = ((stp->sd_read_opt & RD_MSGDIS) ? RMSGD :
43680Sstevel@tonic-gate 		    ((stp->sd_read_opt & RD_MSGNODIS) ? RMSGN : RNORM));
43690Sstevel@tonic-gate 		rdopt |= ((stp->sd_read_opt & RD_PROTDAT) ? RPROTDAT :
43700Sstevel@tonic-gate 		    ((stp->sd_read_opt & RD_PROTDIS) ? RPROTDIS : RPROTNORM));
43710Sstevel@tonic-gate 
43720Sstevel@tonic-gate 		return (strcopyout(&rdopt, (void *)arg, sizeof (int),
43730Sstevel@tonic-gate 		    copyflag));
43740Sstevel@tonic-gate 	    }
43750Sstevel@tonic-gate 
43760Sstevel@tonic-gate 	case I_SERROPT:
43770Sstevel@tonic-gate 		/*
43780Sstevel@tonic-gate 		 * Set error options
43790Sstevel@tonic-gate 		 *
43800Sstevel@tonic-gate 		 * RERRNORM - persistent read errors
43810Sstevel@tonic-gate 		 * RERRNONPERSIST - non-persistent read errors
43820Sstevel@tonic-gate 		 * WERRNORM - persistent write errors
43830Sstevel@tonic-gate 		 * WERRNONPERSIST - non-persistent write errors
43840Sstevel@tonic-gate 		 */
43850Sstevel@tonic-gate 		if (arg & ~(RERRMASK | WERRMASK))
43860Sstevel@tonic-gate 			return (EINVAL);
43870Sstevel@tonic-gate 
43880Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
43890Sstevel@tonic-gate 		switch (arg & RERRMASK) {
43900Sstevel@tonic-gate 		case RERRNORM:
43910Sstevel@tonic-gate 			stp->sd_flag &= ~STRDERRNONPERSIST;
43920Sstevel@tonic-gate 			break;
43930Sstevel@tonic-gate 		case RERRNONPERSIST:
43940Sstevel@tonic-gate 			stp->sd_flag |= STRDERRNONPERSIST;
43950Sstevel@tonic-gate 			break;
43960Sstevel@tonic-gate 		}
43970Sstevel@tonic-gate 		switch (arg & WERRMASK) {
43980Sstevel@tonic-gate 		case WERRNORM:
43990Sstevel@tonic-gate 			stp->sd_flag &= ~STWRERRNONPERSIST;
44000Sstevel@tonic-gate 			break;
44010Sstevel@tonic-gate 		case WERRNONPERSIST:
44020Sstevel@tonic-gate 			stp->sd_flag |= STWRERRNONPERSIST;
44030Sstevel@tonic-gate 			break;
44040Sstevel@tonic-gate 		}
44050Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
44060Sstevel@tonic-gate 		return (0);
44070Sstevel@tonic-gate 
44080Sstevel@tonic-gate 	case I_GERROPT:
44090Sstevel@tonic-gate 		/*
44100Sstevel@tonic-gate 		 * Get error option and return the value
44110Sstevel@tonic-gate 		 * to spot pointed to by arg
44120Sstevel@tonic-gate 		 */
44130Sstevel@tonic-gate 	    {
44140Sstevel@tonic-gate 		int erropt = 0;
44150Sstevel@tonic-gate 
44160Sstevel@tonic-gate 		erropt |= (stp->sd_flag & STRDERRNONPERSIST) ? RERRNONPERSIST :
44170Sstevel@tonic-gate 			RERRNORM;
44180Sstevel@tonic-gate 		erropt |= (stp->sd_flag & STWRERRNONPERSIST) ? WERRNONPERSIST :
44190Sstevel@tonic-gate 			WERRNORM;
44200Sstevel@tonic-gate 		return (strcopyout(&erropt, (void *)arg, sizeof (int),
44210Sstevel@tonic-gate 		    copyflag));
44220Sstevel@tonic-gate 	    }
44230Sstevel@tonic-gate 
44240Sstevel@tonic-gate 	case I_SETSIG:
44250Sstevel@tonic-gate 		/*
44260Sstevel@tonic-gate 		 * Register the calling proc to receive the SIGPOLL
44270Sstevel@tonic-gate 		 * signal based on the events given in arg.  If
44280Sstevel@tonic-gate 		 * arg is zero, remove the proc from register list.
44290Sstevel@tonic-gate 		 */
44300Sstevel@tonic-gate 	    {
44310Sstevel@tonic-gate 		strsig_t *ssp, *pssp;
44320Sstevel@tonic-gate 		struct pid *pidp;
44330Sstevel@tonic-gate 
44340Sstevel@tonic-gate 		pssp = NULL;
44350Sstevel@tonic-gate 		pidp = curproc->p_pidp;
44360Sstevel@tonic-gate 		/*
44370Sstevel@tonic-gate 		 * Hold sd_lock to prevent traversal of sd_siglist while
44380Sstevel@tonic-gate 		 * it is modified.
44390Sstevel@tonic-gate 		 */
44400Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
44410Sstevel@tonic-gate 		for (ssp = stp->sd_siglist; ssp && (ssp->ss_pidp != pidp);
44420Sstevel@tonic-gate 			pssp = ssp, ssp = ssp->ss_next)
44430Sstevel@tonic-gate 			;
44440Sstevel@tonic-gate 
44450Sstevel@tonic-gate 		if (arg) {
44460Sstevel@tonic-gate 			if (arg & ~(S_INPUT|S_HIPRI|S_MSG|S_HANGUP|S_ERROR|
44470Sstevel@tonic-gate 			    S_RDNORM|S_WRNORM|S_RDBAND|S_WRBAND|S_BANDURG)) {
44480Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
44490Sstevel@tonic-gate 				return (EINVAL);
44500Sstevel@tonic-gate 			}
44510Sstevel@tonic-gate 			if ((arg & S_BANDURG) && !(arg & S_RDBAND)) {
44520Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
44530Sstevel@tonic-gate 				return (EINVAL);
44540Sstevel@tonic-gate 			}
44550Sstevel@tonic-gate 
44560Sstevel@tonic-gate 			/*
44570Sstevel@tonic-gate 			 * If proc not already registered, add it
44580Sstevel@tonic-gate 			 * to list.
44590Sstevel@tonic-gate 			 */
44600Sstevel@tonic-gate 			if (!ssp) {
44610Sstevel@tonic-gate 				ssp = kmem_alloc(sizeof (strsig_t), KM_SLEEP);
44620Sstevel@tonic-gate 				ssp->ss_pidp = pidp;
44630Sstevel@tonic-gate 				ssp->ss_pid = pidp->pid_id;
44640Sstevel@tonic-gate 				ssp->ss_next = NULL;
44650Sstevel@tonic-gate 				if (pssp)
44660Sstevel@tonic-gate 					pssp->ss_next = ssp;
44670Sstevel@tonic-gate 				else
44680Sstevel@tonic-gate 					stp->sd_siglist = ssp;
44690Sstevel@tonic-gate 				mutex_enter(&pidlock);
44700Sstevel@tonic-gate 				PID_HOLD(pidp);
44710Sstevel@tonic-gate 				mutex_exit(&pidlock);
44720Sstevel@tonic-gate 			}
44730Sstevel@tonic-gate 
44740Sstevel@tonic-gate 			/*
44750Sstevel@tonic-gate 			 * Set events.
44760Sstevel@tonic-gate 			 */
44770Sstevel@tonic-gate 			ssp->ss_events = (int)arg;
44780Sstevel@tonic-gate 		} else {
44790Sstevel@tonic-gate 			/*
44800Sstevel@tonic-gate 			 * Remove proc from register list.
44810Sstevel@tonic-gate 			 */
44820Sstevel@tonic-gate 			if (ssp) {
44830Sstevel@tonic-gate 				mutex_enter(&pidlock);
44840Sstevel@tonic-gate 				PID_RELE(pidp);
44850Sstevel@tonic-gate 				mutex_exit(&pidlock);
44860Sstevel@tonic-gate 				if (pssp)
44870Sstevel@tonic-gate 					pssp->ss_next = ssp->ss_next;
44880Sstevel@tonic-gate 				else
44890Sstevel@tonic-gate 					stp->sd_siglist = ssp->ss_next;
44900Sstevel@tonic-gate 				kmem_free(ssp, sizeof (strsig_t));
44910Sstevel@tonic-gate 			} else {
44920Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
44930Sstevel@tonic-gate 				return (EINVAL);
44940Sstevel@tonic-gate 			}
44950Sstevel@tonic-gate 		}
44960Sstevel@tonic-gate 
44970Sstevel@tonic-gate 		/*
44980Sstevel@tonic-gate 		 * Recalculate OR of sig events.
44990Sstevel@tonic-gate 		 */
45000Sstevel@tonic-gate 		stp->sd_sigflags = 0;
45010Sstevel@tonic-gate 		for (ssp = stp->sd_siglist; ssp; ssp = ssp->ss_next)
45020Sstevel@tonic-gate 			stp->sd_sigflags |= ssp->ss_events;
45030Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
45040Sstevel@tonic-gate 		return (0);
45050Sstevel@tonic-gate 	    }
45060Sstevel@tonic-gate 
45070Sstevel@tonic-gate 	case I_GETSIG:
45080Sstevel@tonic-gate 		/*
45090Sstevel@tonic-gate 		 * Return (in arg) the current registration of events
45100Sstevel@tonic-gate 		 * for which the calling proc is to be signaled.
45110Sstevel@tonic-gate 		 */
45120Sstevel@tonic-gate 	    {
45130Sstevel@tonic-gate 		struct strsig *ssp;
45140Sstevel@tonic-gate 		struct pid  *pidp;
45150Sstevel@tonic-gate 
45160Sstevel@tonic-gate 		pidp = curproc->p_pidp;
45170Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
45180Sstevel@tonic-gate 		for (ssp = stp->sd_siglist; ssp; ssp = ssp->ss_next)
45190Sstevel@tonic-gate 			if (ssp->ss_pidp == pidp) {
45200Sstevel@tonic-gate 				error = strcopyout(&ssp->ss_events, (void *)arg,
45210Sstevel@tonic-gate 				    sizeof (int), copyflag);
45220Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
45230Sstevel@tonic-gate 				return (error);
45240Sstevel@tonic-gate 			}
45250Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
45260Sstevel@tonic-gate 		return (EINVAL);
45270Sstevel@tonic-gate 	    }
45280Sstevel@tonic-gate 
45290Sstevel@tonic-gate 	case I_ESETSIG:
45300Sstevel@tonic-gate 		/*
45310Sstevel@tonic-gate 		 * Register the ss_pid to receive the SIGPOLL
45320Sstevel@tonic-gate 		 * signal based on the events is ss_events arg.  If
45330Sstevel@tonic-gate 		 * ss_events is zero, remove the proc from register list.
45340Sstevel@tonic-gate 		 */
45350Sstevel@tonic-gate 	{
45360Sstevel@tonic-gate 		struct strsig *ssp, *pssp;
45370Sstevel@tonic-gate 		struct proc *proc;
45380Sstevel@tonic-gate 		struct pid  *pidp;
45390Sstevel@tonic-gate 		pid_t pid;
45400Sstevel@tonic-gate 		struct strsigset ss;
45410Sstevel@tonic-gate 
45420Sstevel@tonic-gate 		error = strcopyin((void *)arg, &ss, sizeof (ss), copyflag);
45430Sstevel@tonic-gate 		if (error)
45440Sstevel@tonic-gate 			return (error);
45450Sstevel@tonic-gate 
45460Sstevel@tonic-gate 		pid = ss.ss_pid;
45470Sstevel@tonic-gate 
45480Sstevel@tonic-gate 		if (ss.ss_events != 0) {
45490Sstevel@tonic-gate 			/*
45500Sstevel@tonic-gate 			 * Permissions check by sending signal 0.
45510Sstevel@tonic-gate 			 * Note that when kill fails it does a set_errno
45520Sstevel@tonic-gate 			 * causing the system call to fail.
45530Sstevel@tonic-gate 			 */
45540Sstevel@tonic-gate 			error = kill(pid, 0);
45550Sstevel@tonic-gate 			if (error) {
45560Sstevel@tonic-gate 				return (error);
45570Sstevel@tonic-gate 			}
45580Sstevel@tonic-gate 		}
45590Sstevel@tonic-gate 		mutex_enter(&pidlock);
45600Sstevel@tonic-gate 		if (pid == 0)
45610Sstevel@tonic-gate 			proc = curproc;
45620Sstevel@tonic-gate 		else if (pid < 0)
45630Sstevel@tonic-gate 			proc = pgfind(-pid);
45640Sstevel@tonic-gate 		else
45650Sstevel@tonic-gate 			proc = prfind(pid);
45660Sstevel@tonic-gate 		if (proc == NULL) {
45670Sstevel@tonic-gate 			mutex_exit(&pidlock);
45680Sstevel@tonic-gate 			return (ESRCH);
45690Sstevel@tonic-gate 		}
45700Sstevel@tonic-gate 		if (pid < 0)
45710Sstevel@tonic-gate 			pidp = proc->p_pgidp;
45720Sstevel@tonic-gate 		else
45730Sstevel@tonic-gate 			pidp = proc->p_pidp;
45740Sstevel@tonic-gate 		ASSERT(pidp);
45750Sstevel@tonic-gate 		/*
45760Sstevel@tonic-gate 		 * Get a hold on the pid structure while referencing it.
45770Sstevel@tonic-gate 		 * There is a separate PID_HOLD should it be inserted
45780Sstevel@tonic-gate 		 * in the list below.
45790Sstevel@tonic-gate 		 */
45800Sstevel@tonic-gate 		PID_HOLD(pidp);
45810Sstevel@tonic-gate 		mutex_exit(&pidlock);
45820Sstevel@tonic-gate 
45830Sstevel@tonic-gate 		pssp = NULL;
45840Sstevel@tonic-gate 		/*
45850Sstevel@tonic-gate 		 * Hold sd_lock to prevent traversal of sd_siglist while
45860Sstevel@tonic-gate 		 * it is modified.
45870Sstevel@tonic-gate 		 */
45880Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
45890Sstevel@tonic-gate 		for (ssp = stp->sd_siglist; ssp && (ssp->ss_pid != pid);
45900Sstevel@tonic-gate 				pssp = ssp, ssp = ssp->ss_next)
45910Sstevel@tonic-gate 			;
45920Sstevel@tonic-gate 
45930Sstevel@tonic-gate 		if (ss.ss_events) {
45940Sstevel@tonic-gate 			if (ss.ss_events &
45950Sstevel@tonic-gate 			    ~(S_INPUT|S_HIPRI|S_MSG|S_HANGUP|S_ERROR|
45960Sstevel@tonic-gate 			    S_RDNORM|S_WRNORM|S_RDBAND|S_WRBAND|S_BANDURG)) {
45970Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
45980Sstevel@tonic-gate 				mutex_enter(&pidlock);
45990Sstevel@tonic-gate 				PID_RELE(pidp);
46000Sstevel@tonic-gate 				mutex_exit(&pidlock);
46010Sstevel@tonic-gate 				return (EINVAL);
46020Sstevel@tonic-gate 			}
46030Sstevel@tonic-gate 			if ((ss.ss_events & S_BANDURG) &&
46040Sstevel@tonic-gate 			    !(ss.ss_events & S_RDBAND)) {
46050Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
46060Sstevel@tonic-gate 				mutex_enter(&pidlock);
46070Sstevel@tonic-gate 				PID_RELE(pidp);
46080Sstevel@tonic-gate 				mutex_exit(&pidlock);
46090Sstevel@tonic-gate 				return (EINVAL);
46100Sstevel@tonic-gate 			}
46110Sstevel@tonic-gate 
46120Sstevel@tonic-gate 			/*
46130Sstevel@tonic-gate 			 * If proc not already registered, add it
46140Sstevel@tonic-gate 			 * to list.
46150Sstevel@tonic-gate 			 */
46160Sstevel@tonic-gate 			if (!ssp) {
46170Sstevel@tonic-gate 				ssp = kmem_alloc(sizeof (strsig_t), KM_SLEEP);
46180Sstevel@tonic-gate 				ssp->ss_pidp = pidp;
46190Sstevel@tonic-gate 				ssp->ss_pid = pid;
46200Sstevel@tonic-gate 				ssp->ss_next = NULL;
46210Sstevel@tonic-gate 				if (pssp)
46220Sstevel@tonic-gate 					pssp->ss_next = ssp;
46230Sstevel@tonic-gate 				else
46240Sstevel@tonic-gate 					stp->sd_siglist = ssp;
46250Sstevel@tonic-gate 				mutex_enter(&pidlock);
46260Sstevel@tonic-gate 				PID_HOLD(pidp);
46270Sstevel@tonic-gate 				mutex_exit(&pidlock);
46280Sstevel@tonic-gate 			}
46290Sstevel@tonic-gate 
46300Sstevel@tonic-gate 			/*
46310Sstevel@tonic-gate 			 * Set events.
46320Sstevel@tonic-gate 			 */
46330Sstevel@tonic-gate 			ssp->ss_events = ss.ss_events;
46340Sstevel@tonic-gate 		} else {
46350Sstevel@tonic-gate 			/*
46360Sstevel@tonic-gate 			 * Remove proc from register list.
46370Sstevel@tonic-gate 			 */
46380Sstevel@tonic-gate 			if (ssp) {
46390Sstevel@tonic-gate 				mutex_enter(&pidlock);
46400Sstevel@tonic-gate 				PID_RELE(pidp);
46410Sstevel@tonic-gate 				mutex_exit(&pidlock);
46420Sstevel@tonic-gate 				if (pssp)
46430Sstevel@tonic-gate 					pssp->ss_next = ssp->ss_next;
46440Sstevel@tonic-gate 				else
46450Sstevel@tonic-gate 					stp->sd_siglist = ssp->ss_next;
46460Sstevel@tonic-gate 				kmem_free(ssp, sizeof (strsig_t));
46470Sstevel@tonic-gate 			} else {
46480Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
46490Sstevel@tonic-gate 				mutex_enter(&pidlock);
46500Sstevel@tonic-gate 				PID_RELE(pidp);
46510Sstevel@tonic-gate 				mutex_exit(&pidlock);
46520Sstevel@tonic-gate 				return (EINVAL);
46530Sstevel@tonic-gate 			}
46540Sstevel@tonic-gate 		}
46550Sstevel@tonic-gate 
46560Sstevel@tonic-gate 		/*
46570Sstevel@tonic-gate 		 * Recalculate OR of sig events.
46580Sstevel@tonic-gate 		 */
46590Sstevel@tonic-gate 		stp->sd_sigflags = 0;
46600Sstevel@tonic-gate 		for (ssp = stp->sd_siglist; ssp; ssp = ssp->ss_next)
46610Sstevel@tonic-gate 			stp->sd_sigflags |= ssp->ss_events;
46620Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
46630Sstevel@tonic-gate 		mutex_enter(&pidlock);
46640Sstevel@tonic-gate 		PID_RELE(pidp);
46650Sstevel@tonic-gate 		mutex_exit(&pidlock);
46660Sstevel@tonic-gate 		return (0);
46670Sstevel@tonic-gate 	    }
46680Sstevel@tonic-gate 
46690Sstevel@tonic-gate 	case I_EGETSIG:
46700Sstevel@tonic-gate 		/*
46710Sstevel@tonic-gate 		 * Return (in arg) the current registration of events
46720Sstevel@tonic-gate 		 * for which the calling proc is to be signaled.
46730Sstevel@tonic-gate 		 */
46740Sstevel@tonic-gate 	    {
46750Sstevel@tonic-gate 		struct strsig *ssp;
46760Sstevel@tonic-gate 		struct proc *proc;
46770Sstevel@tonic-gate 		pid_t pid;
46780Sstevel@tonic-gate 		struct pid  *pidp;
46790Sstevel@tonic-gate 		struct strsigset ss;
46800Sstevel@tonic-gate 
46810Sstevel@tonic-gate 		error = strcopyin((void *)arg, &ss, sizeof (ss), copyflag);
46820Sstevel@tonic-gate 		if (error)
46830Sstevel@tonic-gate 			return (error);
46840Sstevel@tonic-gate 
46850Sstevel@tonic-gate 		pid = ss.ss_pid;
46860Sstevel@tonic-gate 		mutex_enter(&pidlock);
46870Sstevel@tonic-gate 		if (pid == 0)
46880Sstevel@tonic-gate 			proc = curproc;
46890Sstevel@tonic-gate 		else if (pid < 0)
46900Sstevel@tonic-gate 			proc = pgfind(-pid);
46910Sstevel@tonic-gate 		else
46920Sstevel@tonic-gate 			proc = prfind(pid);
46930Sstevel@tonic-gate 		if (proc == NULL) {
46940Sstevel@tonic-gate 			mutex_exit(&pidlock);
46950Sstevel@tonic-gate 			return (ESRCH);
46960Sstevel@tonic-gate 		}
46970Sstevel@tonic-gate 		if (pid < 0)
46980Sstevel@tonic-gate 			pidp = proc->p_pgidp;
46990Sstevel@tonic-gate 		else
47000Sstevel@tonic-gate 			pidp = proc->p_pidp;
47010Sstevel@tonic-gate 
47020Sstevel@tonic-gate 		/* Prevent the pidp from being reassigned */
47030Sstevel@tonic-gate 		PID_HOLD(pidp);
47040Sstevel@tonic-gate 		mutex_exit(&pidlock);
47050Sstevel@tonic-gate 
47060Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
47070Sstevel@tonic-gate 		for (ssp = stp->sd_siglist; ssp; ssp = ssp->ss_next)
47080Sstevel@tonic-gate 			if (ssp->ss_pid == pid) {
47090Sstevel@tonic-gate 				ss.ss_pid = ssp->ss_pid;
47100Sstevel@tonic-gate 				ss.ss_events = ssp->ss_events;
47110Sstevel@tonic-gate 				error = strcopyout(&ss, (void *)arg,
47120Sstevel@tonic-gate 				    sizeof (struct strsigset), copyflag);
47130Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
47140Sstevel@tonic-gate 				mutex_enter(&pidlock);
47150Sstevel@tonic-gate 				PID_RELE(pidp);
47160Sstevel@tonic-gate 				mutex_exit(&pidlock);
47170Sstevel@tonic-gate 				return (error);
47180Sstevel@tonic-gate 			}
47190Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
47200Sstevel@tonic-gate 		mutex_enter(&pidlock);
47210Sstevel@tonic-gate 		PID_RELE(pidp);
47220Sstevel@tonic-gate 		mutex_exit(&pidlock);
47230Sstevel@tonic-gate 		return (EINVAL);
47240Sstevel@tonic-gate 	    }
47250Sstevel@tonic-gate 
47260Sstevel@tonic-gate 	case I_PEEK:
47270Sstevel@tonic-gate 	    {
47280Sstevel@tonic-gate 		STRUCT_DECL(strpeek, strpeek);
47290Sstevel@tonic-gate 		size_t n;
47300Sstevel@tonic-gate 		mblk_t *fmp, *tmp_mp = NULL;
47310Sstevel@tonic-gate 
47320Sstevel@tonic-gate 		STRUCT_INIT(strpeek, flag);
47330Sstevel@tonic-gate 
47340Sstevel@tonic-gate 		error = strcopyin((void *)arg, STRUCT_BUF(strpeek),
47350Sstevel@tonic-gate 		    STRUCT_SIZE(strpeek), copyflag);
47360Sstevel@tonic-gate 		if (error)
47370Sstevel@tonic-gate 			return (error);
47380Sstevel@tonic-gate 
47390Sstevel@tonic-gate 		mutex_enter(QLOCK(rdq));
47400Sstevel@tonic-gate 		/*
47410Sstevel@tonic-gate 		 * Skip the invalid messages
47420Sstevel@tonic-gate 		 */
47430Sstevel@tonic-gate 		for (mp = rdq->q_first; mp != NULL; mp = mp->b_next)
47440Sstevel@tonic-gate 			if (mp->b_datap->db_type != M_SIG)
47450Sstevel@tonic-gate 				break;
47460Sstevel@tonic-gate 
47470Sstevel@tonic-gate 		/*
47480Sstevel@tonic-gate 		 * If user has requested to peek at a high priority message
47490Sstevel@tonic-gate 		 * and first message is not, return 0
47500Sstevel@tonic-gate 		 */
47510Sstevel@tonic-gate 		if (mp != NULL) {
47520Sstevel@tonic-gate 			if ((STRUCT_FGET(strpeek, flags) & RS_HIPRI) &&
47530Sstevel@tonic-gate 			    queclass(mp) == QNORM) {
47540Sstevel@tonic-gate 				*rvalp = 0;
47550Sstevel@tonic-gate 				mutex_exit(QLOCK(rdq));
47560Sstevel@tonic-gate 				return (0);
47570Sstevel@tonic-gate 			}
47580Sstevel@tonic-gate 		} else if (stp->sd_struiordq == NULL ||
47590Sstevel@tonic-gate 		    (STRUCT_FGET(strpeek, flags) & RS_HIPRI)) {
47600Sstevel@tonic-gate 			/*
47610Sstevel@tonic-gate 			 * No mblks to look at at the streamhead and
47620Sstevel@tonic-gate 			 * 1). This isn't a synch stream or
47630Sstevel@tonic-gate 			 * 2). This is a synch stream but caller wants high
47640Sstevel@tonic-gate 			 *	priority messages which is not supported by
47650Sstevel@tonic-gate 			 *	the synch stream. (it only supports QNORM)
47660Sstevel@tonic-gate 			 */
47670Sstevel@tonic-gate 			*rvalp = 0;
47680Sstevel@tonic-gate 			mutex_exit(QLOCK(rdq));
47690Sstevel@tonic-gate 			return (0);
47700Sstevel@tonic-gate 		}
47710Sstevel@tonic-gate 
47720Sstevel@tonic-gate 		fmp = mp;
47730Sstevel@tonic-gate 
47740Sstevel@tonic-gate 		if (mp && mp->b_datap->db_type == M_PASSFP) {
47750Sstevel@tonic-gate 			mutex_exit(QLOCK(rdq));
47760Sstevel@tonic-gate 			return (EBADMSG);
47770Sstevel@tonic-gate 		}
47780Sstevel@tonic-gate 
47790Sstevel@tonic-gate 		ASSERT(mp == NULL || mp->b_datap->db_type == M_PCPROTO ||
47800Sstevel@tonic-gate 		    mp->b_datap->db_type == M_PROTO ||
47810Sstevel@tonic-gate 		    mp->b_datap->db_type == M_DATA);
47820Sstevel@tonic-gate 
47830Sstevel@tonic-gate 		if (mp && mp->b_datap->db_type == M_PCPROTO) {
47840Sstevel@tonic-gate 			STRUCT_FSET(strpeek, flags, RS_HIPRI);
47850Sstevel@tonic-gate 		} else {
47860Sstevel@tonic-gate 			STRUCT_FSET(strpeek, flags, 0);
47870Sstevel@tonic-gate 		}
47880Sstevel@tonic-gate 
47890Sstevel@tonic-gate 
47900Sstevel@tonic-gate 		if (mp && ((tmp_mp = dupmsg(mp)) == NULL)) {
47910Sstevel@tonic-gate 			mutex_exit(QLOCK(rdq));
47920Sstevel@tonic-gate 			return (ENOSR);
47930Sstevel@tonic-gate 		}
47940Sstevel@tonic-gate 		mutex_exit(QLOCK(rdq));
47950Sstevel@tonic-gate 
47960Sstevel@tonic-gate 		/*
47970Sstevel@tonic-gate 		 * set mp = tmp_mp, so that I_PEEK processing can continue.
47980Sstevel@tonic-gate 		 * tmp_mp is used to free the dup'd message.
47990Sstevel@tonic-gate 		 */
48000Sstevel@tonic-gate 		mp = tmp_mp;
48010Sstevel@tonic-gate 
48020Sstevel@tonic-gate 		uio.uio_fmode = 0;
48030Sstevel@tonic-gate 		uio.uio_extflg = UIO_COPY_CACHED;
48040Sstevel@tonic-gate 		uio.uio_segflg = (copyflag == U_TO_K) ? UIO_USERSPACE :
48050Sstevel@tonic-gate 		    UIO_SYSSPACE;
48060Sstevel@tonic-gate 		uio.uio_limit = 0;
48070Sstevel@tonic-gate 		/*
48080Sstevel@tonic-gate 		 * First process PROTO blocks, if any.
48090Sstevel@tonic-gate 		 * If user doesn't want to get ctl info by setting maxlen <= 0,
48100Sstevel@tonic-gate 		 * then set len to -1/0 and skip control blocks part.
48110Sstevel@tonic-gate 		 */
48120Sstevel@tonic-gate 		if (STRUCT_FGET(strpeek, ctlbuf.maxlen) < 0)
48130Sstevel@tonic-gate 			STRUCT_FSET(strpeek, ctlbuf.len, -1);
48140Sstevel@tonic-gate 		else if (STRUCT_FGET(strpeek, ctlbuf.maxlen) == 0)
48150Sstevel@tonic-gate 			STRUCT_FSET(strpeek, ctlbuf.len, 0);
48160Sstevel@tonic-gate 		else {
48170Sstevel@tonic-gate 			int	ctl_part = 0;
48180Sstevel@tonic-gate 
48190Sstevel@tonic-gate 			iov.iov_base = STRUCT_FGETP(strpeek, ctlbuf.buf);
48200Sstevel@tonic-gate 			iov.iov_len = STRUCT_FGET(strpeek, ctlbuf.maxlen);
48210Sstevel@tonic-gate 			uio.uio_iov = &iov;
48220Sstevel@tonic-gate 			uio.uio_resid = iov.iov_len;
48230Sstevel@tonic-gate 			uio.uio_loffset = 0;
48240Sstevel@tonic-gate 			uio.uio_iovcnt = 1;
48250Sstevel@tonic-gate 			while (mp && mp->b_datap->db_type != M_DATA &&
48260Sstevel@tonic-gate 			    uio.uio_resid >= 0) {
48270Sstevel@tonic-gate 				ASSERT(STRUCT_FGET(strpeek, flags) == 0 ?
48280Sstevel@tonic-gate 				    mp->b_datap->db_type == M_PROTO :
48290Sstevel@tonic-gate 				    mp->b_datap->db_type == M_PCPROTO);
48300Sstevel@tonic-gate 
48310Sstevel@tonic-gate 				if ((n = MIN(uio.uio_resid,
48320Sstevel@tonic-gate 				    mp->b_wptr - mp->b_rptr)) != 0 &&
48330Sstevel@tonic-gate 				    (error = uiomove((char *)mp->b_rptr, n,
48340Sstevel@tonic-gate 				    UIO_READ, &uio)) != 0) {
48350Sstevel@tonic-gate 					freemsg(tmp_mp);
48360Sstevel@tonic-gate 					return (error);
48370Sstevel@tonic-gate 				}
48380Sstevel@tonic-gate 				ctl_part = 1;
48390Sstevel@tonic-gate 				mp = mp->b_cont;
48400Sstevel@tonic-gate 			}
48410Sstevel@tonic-gate 			/* No ctl message */
48420Sstevel@tonic-gate 			if (ctl_part == 0)
48430Sstevel@tonic-gate 				STRUCT_FSET(strpeek, ctlbuf.len, -1);
48440Sstevel@tonic-gate 			else
48450Sstevel@tonic-gate 				STRUCT_FSET(strpeek, ctlbuf.len,
48460Sstevel@tonic-gate 				    STRUCT_FGET(strpeek, ctlbuf.maxlen) -
48470Sstevel@tonic-gate 				    uio.uio_resid);
48480Sstevel@tonic-gate 		}
48490Sstevel@tonic-gate 
48500Sstevel@tonic-gate 		/*
48510Sstevel@tonic-gate 		 * Now process DATA blocks, if any.
48520Sstevel@tonic-gate 		 * If user doesn't want to get data info by setting maxlen <= 0,
48530Sstevel@tonic-gate 		 * then set len to -1/0 and skip data blocks part.
48540Sstevel@tonic-gate 		 */
48550Sstevel@tonic-gate 		if (STRUCT_FGET(strpeek, databuf.maxlen) < 0)
48560Sstevel@tonic-gate 			STRUCT_FSET(strpeek, databuf.len, -1);
48570Sstevel@tonic-gate 		else if (STRUCT_FGET(strpeek, databuf.maxlen) == 0)
48580Sstevel@tonic-gate 			STRUCT_FSET(strpeek, databuf.len, 0);
48590Sstevel@tonic-gate 		else {
48600Sstevel@tonic-gate 			int	data_part = 0;
48610Sstevel@tonic-gate 
48620Sstevel@tonic-gate 			iov.iov_base = STRUCT_FGETP(strpeek, databuf.buf);
48630Sstevel@tonic-gate 			iov.iov_len = STRUCT_FGET(strpeek, databuf.maxlen);
48640Sstevel@tonic-gate 			uio.uio_iov = &iov;
48650Sstevel@tonic-gate 			uio.uio_resid = iov.iov_len;
48660Sstevel@tonic-gate 			uio.uio_loffset = 0;
48670Sstevel@tonic-gate 			uio.uio_iovcnt = 1;
48680Sstevel@tonic-gate 			while (mp && uio.uio_resid) {
48690Sstevel@tonic-gate 				if (mp->b_datap->db_type == M_DATA) {
48700Sstevel@tonic-gate 					if ((n = MIN(uio.uio_resid,
48710Sstevel@tonic-gate 					    mp->b_wptr - mp->b_rptr)) != 0 &&
48720Sstevel@tonic-gate 					    (error = uiomove((char *)mp->b_rptr,
48730Sstevel@tonic-gate 						n, UIO_READ, &uio)) != 0) {
48740Sstevel@tonic-gate 						freemsg(tmp_mp);
48750Sstevel@tonic-gate 						return (error);
48760Sstevel@tonic-gate 					}
48770Sstevel@tonic-gate 					data_part = 1;
48780Sstevel@tonic-gate 				}
48790Sstevel@tonic-gate 				ASSERT(data_part == 0 ||
48800Sstevel@tonic-gate 				    mp->b_datap->db_type == M_DATA);
48810Sstevel@tonic-gate 				mp = mp->b_cont;
48820Sstevel@tonic-gate 			}
48830Sstevel@tonic-gate 			/* No data message */
48840Sstevel@tonic-gate 			if (data_part == 0)
48850Sstevel@tonic-gate 				STRUCT_FSET(strpeek, databuf.len, -1);
48860Sstevel@tonic-gate 			else
48870Sstevel@tonic-gate 				STRUCT_FSET(strpeek, databuf.len,
48880Sstevel@tonic-gate 				    STRUCT_FGET(strpeek, databuf.maxlen) -
48890Sstevel@tonic-gate 				    uio.uio_resid);
48900Sstevel@tonic-gate 		}
48910Sstevel@tonic-gate 		freemsg(tmp_mp);
48920Sstevel@tonic-gate 
48930Sstevel@tonic-gate 		/*
48940Sstevel@tonic-gate 		 * It is a synch stream and user wants to get
48950Sstevel@tonic-gate 		 * data (maxlen > 0).
48960Sstevel@tonic-gate 		 * uio setup is done by the codes that process DATA
48970Sstevel@tonic-gate 		 * blocks above.
48980Sstevel@tonic-gate 		 */
48990Sstevel@tonic-gate 		if ((fmp == NULL) && STRUCT_FGET(strpeek, databuf.maxlen) > 0) {
49000Sstevel@tonic-gate 			infod_t infod;
49010Sstevel@tonic-gate 
49020Sstevel@tonic-gate 			infod.d_cmd = INFOD_COPYOUT;
49030Sstevel@tonic-gate 			infod.d_res = 0;
49040Sstevel@tonic-gate 			infod.d_uiop = &uio;
49050Sstevel@tonic-gate 			error = infonext(rdq, &infod);
49060Sstevel@tonic-gate 			if (error == EINVAL || error == EBUSY)
49070Sstevel@tonic-gate 				error = 0;
49080Sstevel@tonic-gate 			if (error)
49090Sstevel@tonic-gate 				return (error);
49100Sstevel@tonic-gate 			STRUCT_FSET(strpeek, databuf.len, STRUCT_FGET(strpeek,
49110Sstevel@tonic-gate 			    databuf.maxlen) - uio.uio_resid);
49120Sstevel@tonic-gate 			if (STRUCT_FGET(strpeek, databuf.len) == 0) {
49130Sstevel@tonic-gate 				/*
49140Sstevel@tonic-gate 				 * No data found by the infonext().
49150Sstevel@tonic-gate 				 */
49160Sstevel@tonic-gate 				STRUCT_FSET(strpeek, databuf.len, -1);
49170Sstevel@tonic-gate 			}
49180Sstevel@tonic-gate 		}
49190Sstevel@tonic-gate 		error = strcopyout(STRUCT_BUF(strpeek), (void *)arg,
49200Sstevel@tonic-gate 		    STRUCT_SIZE(strpeek), copyflag);
49210Sstevel@tonic-gate 		if (error) {
49220Sstevel@tonic-gate 			return (error);
49230Sstevel@tonic-gate 		}
49240Sstevel@tonic-gate 		/*
49250Sstevel@tonic-gate 		 * If there is no message retrieved, set return code to 0
49260Sstevel@tonic-gate 		 * otherwise, set it to 1.
49270Sstevel@tonic-gate 		 */
49280Sstevel@tonic-gate 		if (STRUCT_FGET(strpeek, ctlbuf.len) == -1 &&
49290Sstevel@tonic-gate 		    STRUCT_FGET(strpeek, databuf.len) == -1)
49300Sstevel@tonic-gate 			*rvalp = 0;
49310Sstevel@tonic-gate 		else
49320Sstevel@tonic-gate 			*rvalp = 1;
49330Sstevel@tonic-gate 		return (0);
49340Sstevel@tonic-gate 	    }
49350Sstevel@tonic-gate 
49360Sstevel@tonic-gate 	case I_FDINSERT:
49370Sstevel@tonic-gate 	    {
49380Sstevel@tonic-gate 		STRUCT_DECL(strfdinsert, strfdinsert);
49390Sstevel@tonic-gate 		struct file *resftp;
49400Sstevel@tonic-gate 		struct stdata *resstp;
49410Sstevel@tonic-gate 		t_uscalar_t	ival;
49420Sstevel@tonic-gate 		ssize_t msgsize;
49430Sstevel@tonic-gate 		struct strbuf mctl;
49440Sstevel@tonic-gate 
49450Sstevel@tonic-gate 		STRUCT_INIT(strfdinsert, flag);
49460Sstevel@tonic-gate 		if (stp->sd_flag & STRHUP)
49470Sstevel@tonic-gate 			return (ENXIO);
49480Sstevel@tonic-gate 		/*
49490Sstevel@tonic-gate 		 * STRDERR, STWRERR and STPLEX tested above.
49500Sstevel@tonic-gate 		 */
49510Sstevel@tonic-gate 		error = strcopyin((void *)arg, STRUCT_BUF(strfdinsert),
49520Sstevel@tonic-gate 		    STRUCT_SIZE(strfdinsert), copyflag);
49530Sstevel@tonic-gate 		if (error)
49540Sstevel@tonic-gate 			return (error);
49550Sstevel@tonic-gate 
49560Sstevel@tonic-gate 		if (STRUCT_FGET(strfdinsert, offset) < 0 ||
49570Sstevel@tonic-gate 		    (STRUCT_FGET(strfdinsert, offset) %
49580Sstevel@tonic-gate 		    sizeof (t_uscalar_t)) != 0)
49590Sstevel@tonic-gate 			return (EINVAL);
49600Sstevel@tonic-gate 		if ((resftp = getf(STRUCT_FGET(strfdinsert, fildes))) != NULL) {
49610Sstevel@tonic-gate 			if ((resstp = resftp->f_vnode->v_stream) == NULL) {
49620Sstevel@tonic-gate 				releasef(STRUCT_FGET(strfdinsert, fildes));
49630Sstevel@tonic-gate 				return (EINVAL);
49640Sstevel@tonic-gate 			}
49650Sstevel@tonic-gate 		} else
49660Sstevel@tonic-gate 			return (EINVAL);
49670Sstevel@tonic-gate 
49680Sstevel@tonic-gate 		mutex_enter(&resstp->sd_lock);
49690Sstevel@tonic-gate 		if (resstp->sd_flag & (STRDERR|STWRERR|STRHUP|STPLEX)) {
49700Sstevel@tonic-gate 			error = strgeterr(resstp,
49710Sstevel@tonic-gate 					STRDERR|STWRERR|STRHUP|STPLEX, 0);
49720Sstevel@tonic-gate 			if (error != 0) {
49730Sstevel@tonic-gate 				mutex_exit(&resstp->sd_lock);
49740Sstevel@tonic-gate 				releasef(STRUCT_FGET(strfdinsert, fildes));
49750Sstevel@tonic-gate 				return (error);
49760Sstevel@tonic-gate 			}
49770Sstevel@tonic-gate 		}
49780Sstevel@tonic-gate 		mutex_exit(&resstp->sd_lock);
49790Sstevel@tonic-gate 
49800Sstevel@tonic-gate #ifdef	_ILP32
49810Sstevel@tonic-gate 		{
49820Sstevel@tonic-gate 			queue_t	*q;
49830Sstevel@tonic-gate 			queue_t	*mate = NULL;
49840Sstevel@tonic-gate 
49850Sstevel@tonic-gate 			/* get read queue of stream terminus */
49860Sstevel@tonic-gate 			claimstr(resstp->sd_wrq);
49870Sstevel@tonic-gate 			for (q = resstp->sd_wrq->q_next; q->q_next != NULL;
49880Sstevel@tonic-gate 			    q = q->q_next)
49890Sstevel@tonic-gate 				if (!STRMATED(resstp) && STREAM(q) != resstp &&
49900Sstevel@tonic-gate 				    mate == NULL) {
49910Sstevel@tonic-gate 					ASSERT(q->q_qinfo->qi_srvp);
49920Sstevel@tonic-gate 					ASSERT(_OTHERQ(q)->q_qinfo->qi_srvp);
49930Sstevel@tonic-gate 					claimstr(q);
49940Sstevel@tonic-gate 					mate = q;
49950Sstevel@tonic-gate 				}
49960Sstevel@tonic-gate 			q = _RD(q);
49970Sstevel@tonic-gate 			if (mate)
49980Sstevel@tonic-gate 				releasestr(mate);
49990Sstevel@tonic-gate 			releasestr(resstp->sd_wrq);
50000Sstevel@tonic-gate 			ival = (t_uscalar_t)q;
50010Sstevel@tonic-gate 		}
50020Sstevel@tonic-gate #else
50030Sstevel@tonic-gate 		ival = (t_uscalar_t)getminor(resftp->f_vnode->v_rdev);
50040Sstevel@tonic-gate #endif	/* _ILP32 */
50050Sstevel@tonic-gate 
50060Sstevel@tonic-gate 		if (STRUCT_FGET(strfdinsert, ctlbuf.len) <
50070Sstevel@tonic-gate 		    STRUCT_FGET(strfdinsert, offset) + sizeof (t_uscalar_t)) {
50080Sstevel@tonic-gate 			releasef(STRUCT_FGET(strfdinsert, fildes));
50090Sstevel@tonic-gate 			return (EINVAL);
50100Sstevel@tonic-gate 		}
50110Sstevel@tonic-gate 
50120Sstevel@tonic-gate 		/*
50130Sstevel@tonic-gate 		 * Check for legal flag value.
50140Sstevel@tonic-gate 		 */
50150Sstevel@tonic-gate 		if (STRUCT_FGET(strfdinsert, flags) & ~RS_HIPRI) {
50160Sstevel@tonic-gate 			releasef(STRUCT_FGET(strfdinsert, fildes));
50170Sstevel@tonic-gate 			return (EINVAL);
50180Sstevel@tonic-gate 		}
50190Sstevel@tonic-gate 
50200Sstevel@tonic-gate 		/* get these values from those cached in the stream head */
50210Sstevel@tonic-gate 		mutex_enter(QLOCK(stp->sd_wrq));
50220Sstevel@tonic-gate 		rmin = stp->sd_qn_minpsz;
50230Sstevel@tonic-gate 		rmax = stp->sd_qn_maxpsz;
50240Sstevel@tonic-gate 		mutex_exit(QLOCK(stp->sd_wrq));
50250Sstevel@tonic-gate 
50260Sstevel@tonic-gate 		/*
50270Sstevel@tonic-gate 		 * Make sure ctl and data sizes together fall within
50280Sstevel@tonic-gate 		 * the limits of the max and min receive packet sizes
50290Sstevel@tonic-gate 		 * and do not exceed system limit.  A negative data
50300Sstevel@tonic-gate 		 * length means that no data part is to be sent.
50310Sstevel@tonic-gate 		 */
50320Sstevel@tonic-gate 		ASSERT((rmax >= 0) || (rmax == INFPSZ));
50330Sstevel@tonic-gate 		if (rmax == 0) {
50340Sstevel@tonic-gate 			releasef(STRUCT_FGET(strfdinsert, fildes));
50350Sstevel@tonic-gate 			return (ERANGE);
50360Sstevel@tonic-gate 		}
50370Sstevel@tonic-gate 		if ((msgsize = STRUCT_FGET(strfdinsert, databuf.len)) < 0)
50380Sstevel@tonic-gate 			msgsize = 0;
50390Sstevel@tonic-gate 		if ((msgsize < rmin) ||
50400Sstevel@tonic-gate 		    ((msgsize > rmax) && (rmax != INFPSZ)) ||
50410Sstevel@tonic-gate 		    (STRUCT_FGET(strfdinsert, ctlbuf.len) > strctlsz)) {
50420Sstevel@tonic-gate 			releasef(STRUCT_FGET(strfdinsert, fildes));
50430Sstevel@tonic-gate 			return (ERANGE);
50440Sstevel@tonic-gate 		}
50450Sstevel@tonic-gate 
50460Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
50470Sstevel@tonic-gate 		while (!(STRUCT_FGET(strfdinsert, flags) & RS_HIPRI) &&
50480Sstevel@tonic-gate 		    !canputnext(stp->sd_wrq)) {
50490Sstevel@tonic-gate 			if ((error = strwaitq(stp, WRITEWAIT, (ssize_t)0,
50500Sstevel@tonic-gate 			    flag, -1, &done)) != 0 || done) {
50510Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
50520Sstevel@tonic-gate 				releasef(STRUCT_FGET(strfdinsert, fildes));
50530Sstevel@tonic-gate 				return (error);
50540Sstevel@tonic-gate 			}
50550Sstevel@tonic-gate 			if (stp->sd_sidp != NULL &&
50560Sstevel@tonic-gate 			    stp->sd_vnode->v_type != VFIFO) {
50570Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
50580Sstevel@tonic-gate 				if (error = straccess(stp, access)) {
50590Sstevel@tonic-gate 					releasef(
50600Sstevel@tonic-gate 					    STRUCT_FGET(strfdinsert, fildes));
50610Sstevel@tonic-gate 					return (error);
50620Sstevel@tonic-gate 				}
50630Sstevel@tonic-gate 				mutex_enter(&stp->sd_lock);
50640Sstevel@tonic-gate 			}
50650Sstevel@tonic-gate 		}
50660Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
50670Sstevel@tonic-gate 
50680Sstevel@tonic-gate 		/*
50690Sstevel@tonic-gate 		 * Copy strfdinsert.ctlbuf into native form of
50700Sstevel@tonic-gate 		 * ctlbuf to pass down into strmakemsg().
50710Sstevel@tonic-gate 		 */
50720Sstevel@tonic-gate 		mctl.maxlen = STRUCT_FGET(strfdinsert, ctlbuf.maxlen);
50730Sstevel@tonic-gate 		mctl.len = STRUCT_FGET(strfdinsert, ctlbuf.len);
50740Sstevel@tonic-gate 		mctl.buf = STRUCT_FGETP(strfdinsert, ctlbuf.buf);
50750Sstevel@tonic-gate 
50760Sstevel@tonic-gate 		iov.iov_base = STRUCT_FGETP(strfdinsert, databuf.buf);
50770Sstevel@tonic-gate 		iov.iov_len = STRUCT_FGET(strfdinsert, databuf.len);
50780Sstevel@tonic-gate 		uio.uio_iov = &iov;
50790Sstevel@tonic-gate 		uio.uio_iovcnt = 1;
50800Sstevel@tonic-gate 		uio.uio_loffset = 0;
50810Sstevel@tonic-gate 		uio.uio_segflg = (copyflag == U_TO_K) ? UIO_USERSPACE :
50820Sstevel@tonic-gate 		    UIO_SYSSPACE;
50830Sstevel@tonic-gate 		uio.uio_fmode = 0;
50840Sstevel@tonic-gate 		uio.uio_extflg = UIO_COPY_CACHED;
50850Sstevel@tonic-gate 		uio.uio_resid = iov.iov_len;
50860Sstevel@tonic-gate 		if ((error = strmakemsg(&mctl,
50870Sstevel@tonic-gate 		    &msgsize, &uio, stp,
50880Sstevel@tonic-gate 		    STRUCT_FGET(strfdinsert, flags), &mp)) != 0 || !mp) {
50890Sstevel@tonic-gate 			STRUCT_FSET(strfdinsert, databuf.len, msgsize);
50900Sstevel@tonic-gate 			releasef(STRUCT_FGET(strfdinsert, fildes));
50910Sstevel@tonic-gate 			return (error);
50920Sstevel@tonic-gate 		}
50930Sstevel@tonic-gate 
50940Sstevel@tonic-gate 		STRUCT_FSET(strfdinsert, databuf.len, msgsize);
50950Sstevel@tonic-gate 
50960Sstevel@tonic-gate 		/*
50970Sstevel@tonic-gate 		 * Place the possibly reencoded queue pointer 'offset' bytes
50980Sstevel@tonic-gate 		 * from the start of the control portion of the message.
50990Sstevel@tonic-gate 		 */
51000Sstevel@tonic-gate 		*((t_uscalar_t *)(mp->b_rptr +
51010Sstevel@tonic-gate 		    STRUCT_FGET(strfdinsert, offset))) = ival;
51020Sstevel@tonic-gate 
51030Sstevel@tonic-gate 		/*
51040Sstevel@tonic-gate 		 * Put message downstream.
51050Sstevel@tonic-gate 		 */
51060Sstevel@tonic-gate 		stream_willservice(stp);
51070Sstevel@tonic-gate 		putnext(stp->sd_wrq, mp);
51080Sstevel@tonic-gate 		stream_runservice(stp);
51090Sstevel@tonic-gate 		releasef(STRUCT_FGET(strfdinsert, fildes));
51100Sstevel@tonic-gate 		return (error);
51110Sstevel@tonic-gate 	    }
51120Sstevel@tonic-gate 
51130Sstevel@tonic-gate 	case I_SENDFD:
51140Sstevel@tonic-gate 	    {
51150Sstevel@tonic-gate 		struct file *fp;
51160Sstevel@tonic-gate 
51170Sstevel@tonic-gate 		if ((fp = getf((int)arg)) == NULL)
51180Sstevel@tonic-gate 			return (EBADF);
51190Sstevel@tonic-gate 		error = do_sendfp(stp, fp, crp);
51200Sstevel@tonic-gate #ifdef C2_AUDIT
51210Sstevel@tonic-gate 		if (audit_active) {
51220Sstevel@tonic-gate 			audit_fdsend((int)arg, fp, error);
51230Sstevel@tonic-gate 		}
51240Sstevel@tonic-gate #endif
51250Sstevel@tonic-gate 		releasef((int)arg);
51260Sstevel@tonic-gate 		return (error);
51270Sstevel@tonic-gate 	    }
51280Sstevel@tonic-gate 
51290Sstevel@tonic-gate 	case I_RECVFD:
51300Sstevel@tonic-gate 	case I_E_RECVFD:
51310Sstevel@tonic-gate 	    {
51320Sstevel@tonic-gate 		struct k_strrecvfd *srf;
51330Sstevel@tonic-gate 		int i, fd;
51340Sstevel@tonic-gate 
51350Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
51360Sstevel@tonic-gate 		while (!(mp = getq(rdq))) {
51370Sstevel@tonic-gate 			if (stp->sd_flag & (STRHUP|STREOF)) {
51380Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
51390Sstevel@tonic-gate 				return (ENXIO);
51400Sstevel@tonic-gate 			}
51410Sstevel@tonic-gate 			if ((error = strwaitq(stp, GETWAIT, (ssize_t)0,
51420Sstevel@tonic-gate 			    flag, -1, &done)) != 0 || done) {
51430Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
51440Sstevel@tonic-gate 				return (error);
51450Sstevel@tonic-gate 			}
51460Sstevel@tonic-gate 			if (stp->sd_sidp != NULL &&
51470Sstevel@tonic-gate 			    stp->sd_vnode->v_type != VFIFO) {
51480Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
51490Sstevel@tonic-gate 				if (error = straccess(stp, access))
51500Sstevel@tonic-gate 					return (error);
51510Sstevel@tonic-gate 				mutex_enter(&stp->sd_lock);
51520Sstevel@tonic-gate 			}
51530Sstevel@tonic-gate 		}
51540Sstevel@tonic-gate 		if (mp->b_datap->db_type != M_PASSFP) {
51550Sstevel@tonic-gate 			putback(stp, rdq, mp, mp->b_band);
51560Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
51570Sstevel@tonic-gate 			return (EBADMSG);
51580Sstevel@tonic-gate 		}
51590Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
51600Sstevel@tonic-gate 
51610Sstevel@tonic-gate 		srf = (struct k_strrecvfd *)mp->b_rptr;
51620Sstevel@tonic-gate 		if ((fd = ufalloc(0)) == -1) {
51630Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
51640Sstevel@tonic-gate 			putback(stp, rdq, mp, mp->b_band);
51650Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
51660Sstevel@tonic-gate 			return (EMFILE);
51670Sstevel@tonic-gate 		}
51680Sstevel@tonic-gate 		if (cmd == I_RECVFD) {
51690Sstevel@tonic-gate 			struct o_strrecvfd	ostrfd;
51700Sstevel@tonic-gate 
51710Sstevel@tonic-gate 			/* check to see if uid/gid values are too large. */
51720Sstevel@tonic-gate 
51730Sstevel@tonic-gate 			if (srf->uid > (o_uid_t)USHRT_MAX ||
51740Sstevel@tonic-gate 			    srf->gid > (o_gid_t)USHRT_MAX) {
51750Sstevel@tonic-gate 				mutex_enter(&stp->sd_lock);
51760Sstevel@tonic-gate 				putback(stp, rdq, mp, mp->b_band);
51770Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
51780Sstevel@tonic-gate 				setf(fd, NULL);	/* release fd entry */
51790Sstevel@tonic-gate 				return (EOVERFLOW);
51800Sstevel@tonic-gate 			}
51810Sstevel@tonic-gate 
51820Sstevel@tonic-gate 			ostrfd.fd = fd;
51830Sstevel@tonic-gate 			ostrfd.uid = (o_uid_t)srf->uid;
51840Sstevel@tonic-gate 			ostrfd.gid = (o_gid_t)srf->gid;
51850Sstevel@tonic-gate 
51860Sstevel@tonic-gate 			/* Null the filler bits */
51870Sstevel@tonic-gate 			for (i = 0; i < 8; i++)
51880Sstevel@tonic-gate 				ostrfd.fill[i] = 0;
51890Sstevel@tonic-gate 
51900Sstevel@tonic-gate 			error = strcopyout(&ostrfd, (void *)arg,
51910Sstevel@tonic-gate 			    sizeof (struct o_strrecvfd), copyflag);
51920Sstevel@tonic-gate 		} else {		/* I_E_RECVFD */
51930Sstevel@tonic-gate 			struct strrecvfd	strfd;
51940Sstevel@tonic-gate 
51950Sstevel@tonic-gate 			strfd.fd = fd;
51960Sstevel@tonic-gate 			strfd.uid = srf->uid;
51970Sstevel@tonic-gate 			strfd.gid = srf->gid;
51980Sstevel@tonic-gate 
51990Sstevel@tonic-gate 			/* null the filler bits */
52000Sstevel@tonic-gate 			for (i = 0; i < 8; i++)
52010Sstevel@tonic-gate 				strfd.fill[i] = 0;
52020Sstevel@tonic-gate 
52030Sstevel@tonic-gate 			error = strcopyout(&strfd, (void *)arg,
52040Sstevel@tonic-gate 			    sizeof (struct strrecvfd), copyflag);
52050Sstevel@tonic-gate 		}
52060Sstevel@tonic-gate 
52070Sstevel@tonic-gate 		if (error) {
52080Sstevel@tonic-gate 			setf(fd, NULL);	/* release fd entry */
52090Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
52100Sstevel@tonic-gate 			putback(stp, rdq, mp, mp->b_band);
52110Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
52120Sstevel@tonic-gate 			return (error);
52130Sstevel@tonic-gate 		}
52140Sstevel@tonic-gate #ifdef C2_AUDIT
52150Sstevel@tonic-gate 		if (audit_active) {
52160Sstevel@tonic-gate 			audit_fdrecv(fd, srf->fp);
52170Sstevel@tonic-gate 		}
52180Sstevel@tonic-gate #endif
52190Sstevel@tonic-gate 
52200Sstevel@tonic-gate 		/*
52210Sstevel@tonic-gate 		 * Always increment f_count since the freemsg() below will
52220Sstevel@tonic-gate 		 * always call free_passfp() which performs a closef().
52230Sstevel@tonic-gate 		 */
52240Sstevel@tonic-gate 		mutex_enter(&srf->fp->f_tlock);
52250Sstevel@tonic-gate 		srf->fp->f_count++;
52260Sstevel@tonic-gate 		mutex_exit(&srf->fp->f_tlock);
52270Sstevel@tonic-gate 		setf(fd, srf->fp);
52280Sstevel@tonic-gate 		freemsg(mp);
52290Sstevel@tonic-gate 		return (0);
52300Sstevel@tonic-gate 	    }
52310Sstevel@tonic-gate 
52320Sstevel@tonic-gate 	case I_SWROPT:
52330Sstevel@tonic-gate 		/*
52340Sstevel@tonic-gate 		 * Set/clear the write options. arg is a bit
52350Sstevel@tonic-gate 		 * mask with any of the following bits set...
52360Sstevel@tonic-gate 		 * 	SNDZERO - send zero length message
52370Sstevel@tonic-gate 		 *	SNDPIPE - send sigpipe to process if
52380Sstevel@tonic-gate 		 *		sd_werror is set and process is
52390Sstevel@tonic-gate 		 *		doing a write or putmsg.
52400Sstevel@tonic-gate 		 * The new stream head write options should reflect
52410Sstevel@tonic-gate 		 * what is in arg.
52420Sstevel@tonic-gate 		 */
52430Sstevel@tonic-gate 		if (arg & ~(SNDZERO|SNDPIPE))
52440Sstevel@tonic-gate 			return (EINVAL);
52450Sstevel@tonic-gate 
52460Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
52470Sstevel@tonic-gate 		stp->sd_wput_opt &= ~(SW_SIGPIPE|SW_SNDZERO);
52480Sstevel@tonic-gate 		if (arg & SNDZERO)
52490Sstevel@tonic-gate 			stp->sd_wput_opt |= SW_SNDZERO;
52500Sstevel@tonic-gate 		if (arg & SNDPIPE)
52510Sstevel@tonic-gate 			stp->sd_wput_opt |= SW_SIGPIPE;
52520Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
52530Sstevel@tonic-gate 		return (0);
52540Sstevel@tonic-gate 
52550Sstevel@tonic-gate 	case I_GWROPT:
52560Sstevel@tonic-gate 	    {
52570Sstevel@tonic-gate 		int wropt = 0;
52580Sstevel@tonic-gate 
52590Sstevel@tonic-gate 		if (stp->sd_wput_opt & SW_SNDZERO)
52600Sstevel@tonic-gate 			wropt |= SNDZERO;
52610Sstevel@tonic-gate 		if (stp->sd_wput_opt & SW_SIGPIPE)
52620Sstevel@tonic-gate 			wropt |= SNDPIPE;
52630Sstevel@tonic-gate 		return (strcopyout(&wropt, (void *)arg, sizeof (wropt),
52640Sstevel@tonic-gate 		    copyflag));
52650Sstevel@tonic-gate 	    }
52660Sstevel@tonic-gate 
52670Sstevel@tonic-gate 	case I_LIST:
52680Sstevel@tonic-gate 		/*
52690Sstevel@tonic-gate 		 * Returns all the modules found on this stream,
52700Sstevel@tonic-gate 		 * upto the driver. If argument is NULL, return the
52710Sstevel@tonic-gate 		 * number of modules (including driver). If argument
52720Sstevel@tonic-gate 		 * is not NULL, copy the names into the structure
52730Sstevel@tonic-gate 		 * provided.
52740Sstevel@tonic-gate 		 */
52750Sstevel@tonic-gate 
52760Sstevel@tonic-gate 	    {
52770Sstevel@tonic-gate 		queue_t *q;
52780Sstevel@tonic-gate 		int num_modules, space_allocated;
52790Sstevel@tonic-gate 		STRUCT_DECL(str_list, strlist);
52800Sstevel@tonic-gate 		struct str_mlist *mlist_ptr;
52810Sstevel@tonic-gate 
52820Sstevel@tonic-gate 		if (arg == NULL) { /* Return number of modules plus driver */
52830Sstevel@tonic-gate 			q = stp->sd_wrq;
52840Sstevel@tonic-gate 			if (stp->sd_vnode->v_type == VFIFO) {
52850Sstevel@tonic-gate 				*rvalp = stp->sd_pushcnt;
52860Sstevel@tonic-gate 			} else {
52870Sstevel@tonic-gate 				*rvalp = stp->sd_pushcnt + 1;
52880Sstevel@tonic-gate 			}
52890Sstevel@tonic-gate 		} else {
52900Sstevel@tonic-gate 			STRUCT_INIT(strlist, flag);
52910Sstevel@tonic-gate 
52920Sstevel@tonic-gate 			error = strcopyin((void *)arg, STRUCT_BUF(strlist),
52930Sstevel@tonic-gate 			    STRUCT_SIZE(strlist), copyflag);
52940Sstevel@tonic-gate 			if (error)
52950Sstevel@tonic-gate 				return (error);
52960Sstevel@tonic-gate 
52970Sstevel@tonic-gate 			space_allocated = STRUCT_FGET(strlist, sl_nmods);
52980Sstevel@tonic-gate 			if ((space_allocated) <= 0)
52990Sstevel@tonic-gate 				return (EINVAL);
53000Sstevel@tonic-gate 			claimstr(stp->sd_wrq);
53010Sstevel@tonic-gate 			q = stp->sd_wrq;
53020Sstevel@tonic-gate 			num_modules = 0;
53030Sstevel@tonic-gate 			while (_SAMESTR(q) && (space_allocated != 0)) {
53040Sstevel@tonic-gate 				char *name =
53050Sstevel@tonic-gate 				    q->q_next->q_qinfo->qi_minfo->mi_idname;
53060Sstevel@tonic-gate 
53070Sstevel@tonic-gate 				mlist_ptr = STRUCT_FGETP(strlist, sl_modlist);
53080Sstevel@tonic-gate 
53090Sstevel@tonic-gate 				error = strcopyout(name, mlist_ptr,
53100Sstevel@tonic-gate 				    strlen(name) + 1, copyflag);
53110Sstevel@tonic-gate 
53120Sstevel@tonic-gate 				if (error) {
53130Sstevel@tonic-gate 					releasestr(stp->sd_wrq);
53140Sstevel@tonic-gate 					return (error);
53150Sstevel@tonic-gate 				}
53160Sstevel@tonic-gate 				q = q->q_next;
53170Sstevel@tonic-gate 				space_allocated--;
53180Sstevel@tonic-gate 				num_modules++;
53190Sstevel@tonic-gate 				mlist_ptr =
53200Sstevel@tonic-gate 				    (struct str_mlist *)((uintptr_t)mlist_ptr +
53210Sstevel@tonic-gate 				    sizeof (struct str_mlist));
53220Sstevel@tonic-gate 				STRUCT_FSETP(strlist, sl_modlist, mlist_ptr);
53230Sstevel@tonic-gate 			}
53240Sstevel@tonic-gate 			releasestr(stp->sd_wrq);
53250Sstevel@tonic-gate 			error = strcopyout(&num_modules, (void *)arg,
53260Sstevel@tonic-gate 			    sizeof (int), copyflag);
53270Sstevel@tonic-gate 		}
53280Sstevel@tonic-gate 		return (error);
53290Sstevel@tonic-gate 	    }
53300Sstevel@tonic-gate 
53310Sstevel@tonic-gate 	case I_CKBAND:
53320Sstevel@tonic-gate 	    {
53330Sstevel@tonic-gate 		queue_t *q;
53340Sstevel@tonic-gate 		qband_t *qbp;
53350Sstevel@tonic-gate 
53360Sstevel@tonic-gate 		if ((arg < 0) || (arg >= NBAND))
53370Sstevel@tonic-gate 			return (EINVAL);
53380Sstevel@tonic-gate 		q = _RD(stp->sd_wrq);
53390Sstevel@tonic-gate 		mutex_enter(QLOCK(q));
53400Sstevel@tonic-gate 		if (arg > (int)q->q_nband) {
53410Sstevel@tonic-gate 			*rvalp = 0;
53420Sstevel@tonic-gate 		} else {
53430Sstevel@tonic-gate 			if (arg == 0) {
53440Sstevel@tonic-gate 				if (q->q_first)
53450Sstevel@tonic-gate 					*rvalp = 1;
53460Sstevel@tonic-gate 				else
53470Sstevel@tonic-gate 					*rvalp = 0;
53480Sstevel@tonic-gate 			} else {
53490Sstevel@tonic-gate 				qbp = q->q_bandp;
53500Sstevel@tonic-gate 				while (--arg > 0)
53510Sstevel@tonic-gate 					qbp = qbp->qb_next;
53520Sstevel@tonic-gate 				if (qbp->qb_first)
53530Sstevel@tonic-gate 					*rvalp = 1;
53540Sstevel@tonic-gate 				else
53550Sstevel@tonic-gate 					*rvalp = 0;
53560Sstevel@tonic-gate 			}
53570Sstevel@tonic-gate 		}
53580Sstevel@tonic-gate 		mutex_exit(QLOCK(q));
53590Sstevel@tonic-gate 		return (0);
53600Sstevel@tonic-gate 	    }
53610Sstevel@tonic-gate 
53620Sstevel@tonic-gate 	case I_GETBAND:
53630Sstevel@tonic-gate 	    {
53640Sstevel@tonic-gate 		int intpri;
53650Sstevel@tonic-gate 		queue_t *q;
53660Sstevel@tonic-gate 
53670Sstevel@tonic-gate 		q = _RD(stp->sd_wrq);
53680Sstevel@tonic-gate 		mutex_enter(QLOCK(q));
53690Sstevel@tonic-gate 		mp = q->q_first;
53700Sstevel@tonic-gate 		if (!mp) {
53710Sstevel@tonic-gate 			mutex_exit(QLOCK(q));
53720Sstevel@tonic-gate 			return (ENODATA);
53730Sstevel@tonic-gate 		}
53740Sstevel@tonic-gate 		intpri = (int)mp->b_band;
53750Sstevel@tonic-gate 		error = strcopyout(&intpri, (void *)arg, sizeof (int),
53760Sstevel@tonic-gate 		    copyflag);
53770Sstevel@tonic-gate 		mutex_exit(QLOCK(q));
53780Sstevel@tonic-gate 		return (error);
53790Sstevel@tonic-gate 	    }
53800Sstevel@tonic-gate 
53810Sstevel@tonic-gate 	case I_ATMARK:
53820Sstevel@tonic-gate 	    {
53830Sstevel@tonic-gate 		queue_t *q;
53840Sstevel@tonic-gate 
53850Sstevel@tonic-gate 		if (arg & ~(ANYMARK|LASTMARK))
53860Sstevel@tonic-gate 			return (EINVAL);
53870Sstevel@tonic-gate 		q = _RD(stp->sd_wrq);
53880Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
53890Sstevel@tonic-gate 		if ((stp->sd_flag & STRATMARK) && (arg == ANYMARK)) {
53900Sstevel@tonic-gate 			*rvalp = 1;
53910Sstevel@tonic-gate 		} else {
53920Sstevel@tonic-gate 			mutex_enter(QLOCK(q));
53930Sstevel@tonic-gate 			mp = q->q_first;
53940Sstevel@tonic-gate 
53950Sstevel@tonic-gate 			if (mp == NULL)
53960Sstevel@tonic-gate 				*rvalp = 0;
53970Sstevel@tonic-gate 			else if ((arg == ANYMARK) && (mp->b_flag & MSGMARK))
53980Sstevel@tonic-gate 				*rvalp = 1;
53990Sstevel@tonic-gate 			else if ((arg == LASTMARK) && (mp == stp->sd_mark))
54000Sstevel@tonic-gate 				*rvalp = 1;
54010Sstevel@tonic-gate 			else
54020Sstevel@tonic-gate 				*rvalp = 0;
54030Sstevel@tonic-gate 			mutex_exit(QLOCK(q));
54040Sstevel@tonic-gate 		}
54050Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
54060Sstevel@tonic-gate 		return (0);
54070Sstevel@tonic-gate 	    }
54080Sstevel@tonic-gate 
54090Sstevel@tonic-gate 	case I_CANPUT:
54100Sstevel@tonic-gate 	    {
54110Sstevel@tonic-gate 		char band;
54120Sstevel@tonic-gate 
54130Sstevel@tonic-gate 		if ((arg < 0) || (arg >= NBAND))
54140Sstevel@tonic-gate 			return (EINVAL);
54150Sstevel@tonic-gate 		band = (char)arg;
54160Sstevel@tonic-gate 		*rvalp = bcanputnext(stp->sd_wrq, band);
54170Sstevel@tonic-gate 		return (0);
54180Sstevel@tonic-gate 	    }
54190Sstevel@tonic-gate 
54200Sstevel@tonic-gate 	case I_SETCLTIME:
54210Sstevel@tonic-gate 	    {
54220Sstevel@tonic-gate 		int closetime;
54230Sstevel@tonic-gate 
54240Sstevel@tonic-gate 		error = strcopyin((void *)arg, &closetime, sizeof (int),
54250Sstevel@tonic-gate 		    copyflag);
54260Sstevel@tonic-gate 		if (error)
54270Sstevel@tonic-gate 			return (error);
54280Sstevel@tonic-gate 		if (closetime < 0)
54290Sstevel@tonic-gate 			return (EINVAL);
54300Sstevel@tonic-gate 
54310Sstevel@tonic-gate 		stp->sd_closetime = closetime;
54320Sstevel@tonic-gate 		return (0);
54330Sstevel@tonic-gate 	    }
54340Sstevel@tonic-gate 
54350Sstevel@tonic-gate 	case I_GETCLTIME:
54360Sstevel@tonic-gate 	    {
54370Sstevel@tonic-gate 		int closetime;
54380Sstevel@tonic-gate 
54390Sstevel@tonic-gate 		closetime = stp->sd_closetime;
54400Sstevel@tonic-gate 		return (strcopyout(&closetime, (void *)arg, sizeof (int),
54410Sstevel@tonic-gate 		    copyflag));
54420Sstevel@tonic-gate 	    }
54430Sstevel@tonic-gate 
54440Sstevel@tonic-gate 	case TIOCGSID:
54450Sstevel@tonic-gate 	{
54460Sstevel@tonic-gate 		pid_t sid;
54470Sstevel@tonic-gate 
54480Sstevel@tonic-gate 		mutex_enter(&pidlock);
54490Sstevel@tonic-gate 		if (stp->sd_sidp == NULL) {
54500Sstevel@tonic-gate 			mutex_exit(&pidlock);
54510Sstevel@tonic-gate 			return (ENOTTY);
54520Sstevel@tonic-gate 		}
54530Sstevel@tonic-gate 		sid = stp->sd_sidp->pid_id;
54540Sstevel@tonic-gate 		mutex_exit(&pidlock);
54550Sstevel@tonic-gate 		return (strcopyout(&sid, (void *)arg, sizeof (pid_t),
54560Sstevel@tonic-gate 		    copyflag));
54570Sstevel@tonic-gate 	}
54580Sstevel@tonic-gate 
54590Sstevel@tonic-gate 	case TIOCSPGRP:
54600Sstevel@tonic-gate 	{
54610Sstevel@tonic-gate 		pid_t pgrp;
54620Sstevel@tonic-gate 		proc_t *q;
54630Sstevel@tonic-gate 		pid_t	sid, fg_pgid, bg_pgid;
54640Sstevel@tonic-gate 
54650Sstevel@tonic-gate 		if (error = strcopyin((void *)arg, &pgrp, sizeof (pid_t),
54660Sstevel@tonic-gate 		    copyflag))
54670Sstevel@tonic-gate 			return (error);
54680Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
54690Sstevel@tonic-gate 		mutex_enter(&pidlock);
54700Sstevel@tonic-gate 		if (stp->sd_sidp != ttoproc(curthread)->p_sessp->s_sidp) {
54710Sstevel@tonic-gate 			mutex_exit(&pidlock);
54720Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
54730Sstevel@tonic-gate 			return (ENOTTY);
54740Sstevel@tonic-gate 		}
54750Sstevel@tonic-gate 		if (pgrp == stp->sd_pgidp->pid_id) {
54760Sstevel@tonic-gate 			mutex_exit(&pidlock);
54770Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
54780Sstevel@tonic-gate 			return (0);
54790Sstevel@tonic-gate 		}
54800Sstevel@tonic-gate 		if (pgrp <= 0 || pgrp >= maxpid) {
54810Sstevel@tonic-gate 			mutex_exit(&pidlock);
54820Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
54830Sstevel@tonic-gate 			return (EINVAL);
54840Sstevel@tonic-gate 		}
54850Sstevel@tonic-gate 		if ((q = pgfind(pgrp)) == NULL ||
54860Sstevel@tonic-gate 		    q->p_sessp != ttoproc(curthread)->p_sessp) {
54870Sstevel@tonic-gate 			mutex_exit(&pidlock);
54880Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
54890Sstevel@tonic-gate 			return (EPERM);
54900Sstevel@tonic-gate 		}
54910Sstevel@tonic-gate 		sid = stp->sd_sidp->pid_id;
54920Sstevel@tonic-gate 		fg_pgid = q->p_pgrp;
54930Sstevel@tonic-gate 		bg_pgid = stp->sd_pgidp->pid_id;
54940Sstevel@tonic-gate 		CL_SET_PROCESS_GROUP(curthread, sid, bg_pgid, fg_pgid);
54950Sstevel@tonic-gate 		PID_RELE(stp->sd_pgidp);
54960Sstevel@tonic-gate 		stp->sd_pgidp = q->p_pgidp;
54970Sstevel@tonic-gate 		PID_HOLD(stp->sd_pgidp);
54980Sstevel@tonic-gate 		mutex_exit(&pidlock);
54990Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
55000Sstevel@tonic-gate 		return (0);
55010Sstevel@tonic-gate 	}
55020Sstevel@tonic-gate 
55030Sstevel@tonic-gate 	case TIOCGPGRP:
55040Sstevel@tonic-gate 	{
55050Sstevel@tonic-gate 		pid_t pgrp;
55060Sstevel@tonic-gate 
55070Sstevel@tonic-gate 		mutex_enter(&pidlock);
55080Sstevel@tonic-gate 		if (stp->sd_sidp == NULL) {
55090Sstevel@tonic-gate 			mutex_exit(&pidlock);
55100Sstevel@tonic-gate 			return (ENOTTY);
55110Sstevel@tonic-gate 		}
55120Sstevel@tonic-gate 		pgrp = stp->sd_pgidp->pid_id;
55130Sstevel@tonic-gate 		mutex_exit(&pidlock);
55140Sstevel@tonic-gate 		return (strcopyout(&pgrp, (void *)arg, sizeof (pid_t),
55150Sstevel@tonic-gate 		    copyflag));
55160Sstevel@tonic-gate 	}
55170Sstevel@tonic-gate 
55180Sstevel@tonic-gate 	case FIONBIO:
55190Sstevel@tonic-gate 	case FIOASYNC:
55200Sstevel@tonic-gate 		return (0);	/* handled by the upper layer */
55210Sstevel@tonic-gate 	}
55220Sstevel@tonic-gate }
55230Sstevel@tonic-gate 
55240Sstevel@tonic-gate /*
55250Sstevel@tonic-gate  * Custom free routine used for M_PASSFP messages.
55260Sstevel@tonic-gate  */
55270Sstevel@tonic-gate static void
55280Sstevel@tonic-gate free_passfp(struct k_strrecvfd *srf)
55290Sstevel@tonic-gate {
55300Sstevel@tonic-gate 	(void) closef(srf->fp);
55310Sstevel@tonic-gate 	kmem_free(srf, sizeof (struct k_strrecvfd) + sizeof (frtn_t));
55320Sstevel@tonic-gate }
55330Sstevel@tonic-gate 
55340Sstevel@tonic-gate /* ARGSUSED */
55350Sstevel@tonic-gate int
55360Sstevel@tonic-gate do_sendfp(struct stdata *stp, struct file *fp, struct cred *cr)
55370Sstevel@tonic-gate {
55380Sstevel@tonic-gate 	queue_t *qp, *nextqp;
55390Sstevel@tonic-gate 	struct k_strrecvfd *srf;
55400Sstevel@tonic-gate 	mblk_t *mp;
55410Sstevel@tonic-gate 	frtn_t *frtnp;
55420Sstevel@tonic-gate 	size_t bufsize;
55430Sstevel@tonic-gate 	queue_t	*mate = NULL;
55440Sstevel@tonic-gate 	syncq_t	*sq = NULL;
55450Sstevel@tonic-gate 	int retval = 0;
55460Sstevel@tonic-gate 
55470Sstevel@tonic-gate 	if (stp->sd_flag & STRHUP)
55480Sstevel@tonic-gate 		return (ENXIO);
55490Sstevel@tonic-gate 
55500Sstevel@tonic-gate 	claimstr(stp->sd_wrq);
55510Sstevel@tonic-gate 
55520Sstevel@tonic-gate 	/* Fastpath, we have a pipe, and we are already mated, use it. */
55530Sstevel@tonic-gate 	if (STRMATED(stp)) {
55540Sstevel@tonic-gate 		qp = _RD(stp->sd_mate->sd_wrq);
55550Sstevel@tonic-gate 		claimstr(qp);
55560Sstevel@tonic-gate 		mate = qp;
55570Sstevel@tonic-gate 	} else { /* Not already mated. */
55580Sstevel@tonic-gate 
55590Sstevel@tonic-gate 		/*
55600Sstevel@tonic-gate 		 * Walk the stream to the end of this one.
55610Sstevel@tonic-gate 		 * assumes that the claimstr() will prevent
55620Sstevel@tonic-gate 		 * plumbing between the stream head and the
55630Sstevel@tonic-gate 		 * driver from changing
55640Sstevel@tonic-gate 		 */
55650Sstevel@tonic-gate 		qp = stp->sd_wrq;
55660Sstevel@tonic-gate 
55670Sstevel@tonic-gate 		/*
55680Sstevel@tonic-gate 		 * Loop until we reach the end of this stream.
55690Sstevel@tonic-gate 		 * On completion, qp points to the write queue
55700Sstevel@tonic-gate 		 * at the end of the stream, or the read queue
55710Sstevel@tonic-gate 		 * at the stream head if this is a fifo.
55720Sstevel@tonic-gate 		 */
55730Sstevel@tonic-gate 		while (((qp = qp->q_next) != NULL) && _SAMESTR(qp))
55740Sstevel@tonic-gate 			;
55750Sstevel@tonic-gate 
55760Sstevel@tonic-gate 		/*
55770Sstevel@tonic-gate 		 * Just in case we get a q_next which is NULL, but
55780Sstevel@tonic-gate 		 * not at the end of the stream.  This is actually
55790Sstevel@tonic-gate 		 * broken, so we set an assert to catch it in
55800Sstevel@tonic-gate 		 * debug, and set an error and return if not debug.
55810Sstevel@tonic-gate 		 */
55820Sstevel@tonic-gate 		ASSERT(qp);
55830Sstevel@tonic-gate 		if (qp == NULL) {
55840Sstevel@tonic-gate 			releasestr(stp->sd_wrq);
55850Sstevel@tonic-gate 			return (EINVAL);
55860Sstevel@tonic-gate 		}
55870Sstevel@tonic-gate 
55880Sstevel@tonic-gate 		/*
55890Sstevel@tonic-gate 		 * Enter the syncq for the driver, so (hopefully)
55900Sstevel@tonic-gate 		 * the queue values will not change on us.
55910Sstevel@tonic-gate 		 * XXXX - This will only prevent the race IFF only
55920Sstevel@tonic-gate 		 *   the write side modifies the q_next member, and
55930Sstevel@tonic-gate 		 *   the put procedure is protected by at least
55940Sstevel@tonic-gate 		 *   MT_PERQ.
55950Sstevel@tonic-gate 		 */
55960Sstevel@tonic-gate 		if ((sq = qp->q_syncq) != NULL)
55970Sstevel@tonic-gate 			entersq(sq, SQ_PUT);
55980Sstevel@tonic-gate 
55990Sstevel@tonic-gate 		/* Now get the q_next value from this qp. */
56000Sstevel@tonic-gate 		nextqp = qp->q_next;
56010Sstevel@tonic-gate 
56020Sstevel@tonic-gate 		/*
56030Sstevel@tonic-gate 		 * If nextqp exists and the other stream is different
56040Sstevel@tonic-gate 		 * from this one claim the stream, set the mate, and
56050Sstevel@tonic-gate 		 * get the read queue at the stream head of the other
56060Sstevel@tonic-gate 		 * stream.  Assumes that nextqp was at least valid when
56070Sstevel@tonic-gate 		 * we got it.  Hopefully the entersq of the driver
56080Sstevel@tonic-gate 		 * will prevent it from changing on us.
56090Sstevel@tonic-gate 		 */
56100Sstevel@tonic-gate 		if ((nextqp != NULL) && (STREAM(nextqp) != stp)) {
56110Sstevel@tonic-gate 			ASSERT(qp->q_qinfo->qi_srvp);
56120Sstevel@tonic-gate 			ASSERT(_OTHERQ(qp)->q_qinfo->qi_srvp);
56130Sstevel@tonic-gate 			ASSERT(_OTHERQ(qp->q_next)->q_qinfo->qi_srvp);
56140Sstevel@tonic-gate 			claimstr(nextqp);
56150Sstevel@tonic-gate 
56160Sstevel@tonic-gate 			/* Make sure we still have a q_next */
56170Sstevel@tonic-gate 			if (nextqp != qp->q_next) {
56180Sstevel@tonic-gate 				releasestr(stp->sd_wrq);
56190Sstevel@tonic-gate 				releasestr(nextqp);
56200Sstevel@tonic-gate 				return (EINVAL);
56210Sstevel@tonic-gate 			}
56220Sstevel@tonic-gate 
56230Sstevel@tonic-gate 			qp = _RD(STREAM(nextqp)->sd_wrq);
56240Sstevel@tonic-gate 			mate = qp;
56250Sstevel@tonic-gate 		}
56260Sstevel@tonic-gate 		/* If we entered the synq above, leave it. */
56270Sstevel@tonic-gate 		if (sq != NULL)
56280Sstevel@tonic-gate 			leavesq(sq, SQ_PUT);
56290Sstevel@tonic-gate 	} /*  STRMATED(STP)  */
56300Sstevel@tonic-gate 
56310Sstevel@tonic-gate 	/* XXX prevents substitution of the ops vector */
56320Sstevel@tonic-gate 	if (qp->q_qinfo != &strdata && qp->q_qinfo != &fifo_strdata) {
56330Sstevel@tonic-gate 		retval = EINVAL;
56340Sstevel@tonic-gate 		goto out;
56350Sstevel@tonic-gate 	}
56360Sstevel@tonic-gate 
56370Sstevel@tonic-gate 	if (qp->q_flag & QFULL) {
56380Sstevel@tonic-gate 		retval = EAGAIN;
56390Sstevel@tonic-gate 		goto out;
56400Sstevel@tonic-gate 	}
56410Sstevel@tonic-gate 
56420Sstevel@tonic-gate 	/*
56430Sstevel@tonic-gate 	 * Since M_PASSFP messages include a file descriptor, we use
56440Sstevel@tonic-gate 	 * esballoc() and specify a custom free routine (free_passfp()) that
56450Sstevel@tonic-gate 	 * will close the descriptor as part of freeing the message.  For
56460Sstevel@tonic-gate 	 * convenience, we stash the frtn_t right after the data block.
56470Sstevel@tonic-gate 	 */
56480Sstevel@tonic-gate 	bufsize = sizeof (struct k_strrecvfd) + sizeof (frtn_t);
56490Sstevel@tonic-gate 	srf = kmem_alloc(bufsize, KM_NOSLEEP);
56500Sstevel@tonic-gate 	if (srf == NULL) {
56510Sstevel@tonic-gate 		retval = EAGAIN;
56520Sstevel@tonic-gate 		goto out;
56530Sstevel@tonic-gate 	}
56540Sstevel@tonic-gate 
56550Sstevel@tonic-gate 	frtnp = (frtn_t *)(srf + 1);
56560Sstevel@tonic-gate 	frtnp->free_arg = (caddr_t)srf;
56570Sstevel@tonic-gate 	frtnp->free_func = free_passfp;
56580Sstevel@tonic-gate 
56590Sstevel@tonic-gate 	mp = esballoc((uchar_t *)srf, bufsize, BPRI_MED, frtnp);
56600Sstevel@tonic-gate 	if (mp == NULL) {
56610Sstevel@tonic-gate 		kmem_free(srf, bufsize);
56620Sstevel@tonic-gate 		retval = EAGAIN;
56630Sstevel@tonic-gate 		goto out;
56640Sstevel@tonic-gate 	}
56650Sstevel@tonic-gate 	mp->b_wptr += sizeof (struct k_strrecvfd);
56660Sstevel@tonic-gate 	mp->b_datap->db_type = M_PASSFP;
56670Sstevel@tonic-gate 
56680Sstevel@tonic-gate 	srf->fp = fp;
56690Sstevel@tonic-gate 	srf->uid = crgetuid(curthread->t_cred);
56700Sstevel@tonic-gate 	srf->gid = crgetgid(curthread->t_cred);
56710Sstevel@tonic-gate 	mutex_enter(&fp->f_tlock);
56720Sstevel@tonic-gate 	fp->f_count++;
56730Sstevel@tonic-gate 	mutex_exit(&fp->f_tlock);
56740Sstevel@tonic-gate 
56750Sstevel@tonic-gate 	put(qp, mp);
56760Sstevel@tonic-gate out:
56770Sstevel@tonic-gate 	releasestr(stp->sd_wrq);
56780Sstevel@tonic-gate 	if (mate)
56790Sstevel@tonic-gate 		releasestr(mate);
56800Sstevel@tonic-gate 	return (retval);
56810Sstevel@tonic-gate }
56820Sstevel@tonic-gate 
56830Sstevel@tonic-gate /*
56840Sstevel@tonic-gate  * Send an ioctl message downstream and wait for acknowledgement.
56850Sstevel@tonic-gate  * flags may be set to either U_TO_K or K_TO_K and a combination
56860Sstevel@tonic-gate  * of STR_NOERROR or STR_NOSIG
56870Sstevel@tonic-gate  * STR_NOSIG: Signals are essentially ignored or held and have
56880Sstevel@tonic-gate  *	no effect for the duration of the call.
56890Sstevel@tonic-gate  * STR_NOERROR: Ignores stream head read, write and hup errors.
56900Sstevel@tonic-gate  *	Additionally, if an existing ioctl times out, it is assumed
56910Sstevel@tonic-gate  *	lost and and this ioctl will continue as if the previous ioctl had
56920Sstevel@tonic-gate  *	finished.  ETIME may be returned if this ioctl times out (i.e.
56930Sstevel@tonic-gate  *	ic_timout is not INFTIM).  Non-stream head errors may be returned if
56940Sstevel@tonic-gate  *	the ioc_error indicates that the driver/module had problems,
56950Sstevel@tonic-gate  *	an EFAULT was found when accessing user data, a lack of
56960Sstevel@tonic-gate  * 	resources, etc.
56970Sstevel@tonic-gate  */
56980Sstevel@tonic-gate int
56990Sstevel@tonic-gate strdoioctl(
57000Sstevel@tonic-gate 	struct stdata *stp,
57010Sstevel@tonic-gate 	struct strioctl *strioc,
57020Sstevel@tonic-gate 	int fflags,		/* file flags with model info */
57030Sstevel@tonic-gate 	int flag,
57040Sstevel@tonic-gate 	cred_t *crp,
57050Sstevel@tonic-gate 	int *rvalp)
57060Sstevel@tonic-gate {
57070Sstevel@tonic-gate 	mblk_t *bp;
57080Sstevel@tonic-gate 	struct iocblk *iocbp;
57090Sstevel@tonic-gate 	struct copyreq *reqp;
57100Sstevel@tonic-gate 	struct copyresp *resp;
57110Sstevel@tonic-gate 	int id;
57120Sstevel@tonic-gate 	int transparent = 0;
57130Sstevel@tonic-gate 	int error = 0;
57140Sstevel@tonic-gate 	int len = 0;
57150Sstevel@tonic-gate 	caddr_t taddr;
57160Sstevel@tonic-gate 	int copyflag = (flag & (U_TO_K | K_TO_K));
57170Sstevel@tonic-gate 	int sigflag = (flag & STR_NOSIG);
57180Sstevel@tonic-gate 	int errs;
57190Sstevel@tonic-gate 	uint_t waitflags;
57200Sstevel@tonic-gate 
57210Sstevel@tonic-gate 	ASSERT(copyflag == U_TO_K || copyflag == K_TO_K);
57220Sstevel@tonic-gate 	ASSERT((fflags & FMODELS) != 0);
57230Sstevel@tonic-gate 
57240Sstevel@tonic-gate 	TRACE_2(TR_FAC_STREAMS_FR,
57250Sstevel@tonic-gate 		TR_STRDOIOCTL,
57260Sstevel@tonic-gate 		"strdoioctl:stp %p strioc %p", stp, strioc);
57270Sstevel@tonic-gate 	if (strioc->ic_len == TRANSPARENT) {	/* send arg in M_DATA block */
57280Sstevel@tonic-gate 		transparent = 1;
57290Sstevel@tonic-gate 		strioc->ic_len = sizeof (intptr_t);
57300Sstevel@tonic-gate 	}
57310Sstevel@tonic-gate 
57320Sstevel@tonic-gate 	if (strioc->ic_len < 0 || (strmsgsz > 0 && strioc->ic_len > strmsgsz))
57330Sstevel@tonic-gate 		return (EINVAL);
57340Sstevel@tonic-gate 
57350Sstevel@tonic-gate 	if ((bp = allocb_cred_wait(sizeof (union ioctypes), sigflag, &error,
57360Sstevel@tonic-gate 	    crp)) == NULL)
57370Sstevel@tonic-gate 			return (error);
57380Sstevel@tonic-gate 
57390Sstevel@tonic-gate 	bzero(bp->b_wptr, sizeof (union ioctypes));
57400Sstevel@tonic-gate 
57410Sstevel@tonic-gate 	iocbp = (struct iocblk *)bp->b_wptr;
57420Sstevel@tonic-gate 	iocbp->ioc_count = strioc->ic_len;
57430Sstevel@tonic-gate 	iocbp->ioc_cmd = strioc->ic_cmd;
57440Sstevel@tonic-gate 	iocbp->ioc_flag = (fflags & FMODELS);
57450Sstevel@tonic-gate 
57460Sstevel@tonic-gate 	crhold(crp);
57470Sstevel@tonic-gate 	iocbp->ioc_cr = crp;
57480Sstevel@tonic-gate 	DB_TYPE(bp) = M_IOCTL;
57490Sstevel@tonic-gate 	DB_CPID(bp) = curproc->p_pid;
57500Sstevel@tonic-gate 	bp->b_wptr += sizeof (struct iocblk);
57510Sstevel@tonic-gate 
57520Sstevel@tonic-gate 	if (flag & STR_NOERROR)
57530Sstevel@tonic-gate 		errs = STPLEX;
57540Sstevel@tonic-gate 	else
57550Sstevel@tonic-gate 		errs = STRHUP|STRDERR|STWRERR|STPLEX;
57560Sstevel@tonic-gate 
57570Sstevel@tonic-gate 	/*
57580Sstevel@tonic-gate 	 * If there is data to copy into ioctl block, do so.
57590Sstevel@tonic-gate 	 */
57600Sstevel@tonic-gate 	if (iocbp->ioc_count > 0) {
57610Sstevel@tonic-gate 		if (transparent)
57620Sstevel@tonic-gate 			/*
57630Sstevel@tonic-gate 			 * Note: STR_NOERROR does not have an effect
57640Sstevel@tonic-gate 			 * in putiocd()
57650Sstevel@tonic-gate 			 */
57660Sstevel@tonic-gate 			id = K_TO_K | sigflag;
57670Sstevel@tonic-gate 		else
57680Sstevel@tonic-gate 			id = flag;
57690Sstevel@tonic-gate 		if ((error = putiocd(bp, strioc->ic_dp, id, crp)) != 0) {
57700Sstevel@tonic-gate 			freemsg(bp);
57710Sstevel@tonic-gate 			crfree(crp);
57720Sstevel@tonic-gate 			return (error);
57730Sstevel@tonic-gate 		}
57740Sstevel@tonic-gate 
57750Sstevel@tonic-gate 		/*
57760Sstevel@tonic-gate 		 * We could have slept copying in user pages.
57770Sstevel@tonic-gate 		 * Recheck the stream head state (the other end
57780Sstevel@tonic-gate 		 * of a pipe could have gone away).
57790Sstevel@tonic-gate 		 */
57800Sstevel@tonic-gate 		if (stp->sd_flag & errs) {
57810Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
57820Sstevel@tonic-gate 			error = strgeterr(stp, errs, 0);
57830Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
57840Sstevel@tonic-gate 			if (error != 0) {
57850Sstevel@tonic-gate 				freemsg(bp);
57860Sstevel@tonic-gate 				crfree(crp);
57870Sstevel@tonic-gate 				return (error);
57880Sstevel@tonic-gate 			}
57890Sstevel@tonic-gate 		}
57900Sstevel@tonic-gate 	}
57910Sstevel@tonic-gate 	if (transparent)
57920Sstevel@tonic-gate 		iocbp->ioc_count = TRANSPARENT;
57930Sstevel@tonic-gate 
57940Sstevel@tonic-gate 	/*
57950Sstevel@tonic-gate 	 * Block for up to STRTIMOUT milliseconds if there is an outstanding
57960Sstevel@tonic-gate 	 * ioctl for this stream already running.  All processes
57970Sstevel@tonic-gate 	 * sleeping here will be awakened as a result of an ACK
57980Sstevel@tonic-gate 	 * or NAK being received for the outstanding ioctl, or
57990Sstevel@tonic-gate 	 * as a result of the timer expiring on the outstanding
58000Sstevel@tonic-gate 	 * ioctl (a failure), or as a result of any waiting
58010Sstevel@tonic-gate 	 * process's timer expiring (also a failure).
58020Sstevel@tonic-gate 	 */
58030Sstevel@tonic-gate 
58040Sstevel@tonic-gate 	error = 0;
58050Sstevel@tonic-gate 	mutex_enter(&stp->sd_lock);
58060Sstevel@tonic-gate 	while (stp->sd_flag & (IOCWAIT | IOCWAITNE)) {
58070Sstevel@tonic-gate 		clock_t cv_rval;
58080Sstevel@tonic-gate 
58090Sstevel@tonic-gate 		TRACE_0(TR_FAC_STREAMS_FR,
58100Sstevel@tonic-gate 			TR_STRDOIOCTL_WAIT,
58110Sstevel@tonic-gate 			"strdoioctl sleeps - IOCWAIT");
58120Sstevel@tonic-gate 		cv_rval = str_cv_wait(&stp->sd_iocmonitor, &stp->sd_lock,
58130Sstevel@tonic-gate 		    STRTIMOUT, sigflag);
58140Sstevel@tonic-gate 		if (cv_rval <= 0) {
58150Sstevel@tonic-gate 			if (cv_rval == 0) {
58160Sstevel@tonic-gate 				error = EINTR;
58170Sstevel@tonic-gate 			} else {
58180Sstevel@tonic-gate 				if (flag & STR_NOERROR) {
58190Sstevel@tonic-gate 					/*
58200Sstevel@tonic-gate 					 * Terminating current ioctl in
58210Sstevel@tonic-gate 					 * progress -- assume it got lost and
58220Sstevel@tonic-gate 					 * wake up the other thread so that the
58230Sstevel@tonic-gate 					 * operation completes.
58240Sstevel@tonic-gate 					 */
58250Sstevel@tonic-gate 					if (!(stp->sd_flag & IOCWAITNE)) {
58260Sstevel@tonic-gate 						stp->sd_flag |= IOCWAITNE;
58270Sstevel@tonic-gate 						cv_broadcast(&stp->sd_monitor);
58280Sstevel@tonic-gate 					}
58290Sstevel@tonic-gate 					/*
58300Sstevel@tonic-gate 					 * Otherwise, there's a running
58310Sstevel@tonic-gate 					 * STR_NOERROR -- we have no choice
58320Sstevel@tonic-gate 					 * here but to wait forever (or until
58330Sstevel@tonic-gate 					 * interrupted).
58340Sstevel@tonic-gate 					 */
58350Sstevel@tonic-gate 				} else {
58360Sstevel@tonic-gate 					/*
58370Sstevel@tonic-gate 					 * pending ioctl has caused
58380Sstevel@tonic-gate 					 * us to time out
58390Sstevel@tonic-gate 					 */
58400Sstevel@tonic-gate 					error = ETIME;
58410Sstevel@tonic-gate 				}
58420Sstevel@tonic-gate 			}
58430Sstevel@tonic-gate 		} else if ((stp->sd_flag & errs)) {
58440Sstevel@tonic-gate 			error = strgeterr(stp, errs, 0);
58450Sstevel@tonic-gate 		}
58460Sstevel@tonic-gate 		if (error) {
58470Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
58480Sstevel@tonic-gate 			freemsg(bp);
58490Sstevel@tonic-gate 			crfree(crp);
58500Sstevel@tonic-gate 			return (error);
58510Sstevel@tonic-gate 		}
58520Sstevel@tonic-gate 	}
58530Sstevel@tonic-gate 
58540Sstevel@tonic-gate 	/*
58550Sstevel@tonic-gate 	 * Have control of ioctl mechanism.
58560Sstevel@tonic-gate 	 * Send down ioctl packet and wait for response.
58570Sstevel@tonic-gate 	 */
58580Sstevel@tonic-gate 	if (stp->sd_iocblk != (mblk_t *)-1) {
58590Sstevel@tonic-gate 		freemsg(stp->sd_iocblk);
58600Sstevel@tonic-gate 	}
58610Sstevel@tonic-gate 	stp->sd_iocblk = NULL;
58620Sstevel@tonic-gate 
58630Sstevel@tonic-gate 	/*
58640Sstevel@tonic-gate 	 * If this is marked with 'noerror' (internal; mostly
58650Sstevel@tonic-gate 	 * I_{P,}{UN,}LINK), then make sure nobody else is able to get
58660Sstevel@tonic-gate 	 * in here by setting IOCWAITNE.
58670Sstevel@tonic-gate 	 */
58680Sstevel@tonic-gate 	waitflags = IOCWAIT;
58690Sstevel@tonic-gate 	if (flag & STR_NOERROR)
58700Sstevel@tonic-gate 		waitflags |= IOCWAITNE;
58710Sstevel@tonic-gate 
58720Sstevel@tonic-gate 	stp->sd_flag |= waitflags;
58730Sstevel@tonic-gate 
58740Sstevel@tonic-gate 	/*
58750Sstevel@tonic-gate 	 * Assign sequence number.
58760Sstevel@tonic-gate 	 */
58770Sstevel@tonic-gate 	iocbp->ioc_id = stp->sd_iocid = getiocseqno();
58780Sstevel@tonic-gate 
58790Sstevel@tonic-gate 	mutex_exit(&stp->sd_lock);
58800Sstevel@tonic-gate 
58810Sstevel@tonic-gate 	TRACE_1(TR_FAC_STREAMS_FR,
58820Sstevel@tonic-gate 		TR_STRDOIOCTL_PUT, "strdoioctl put: stp %p", stp);
58830Sstevel@tonic-gate 	stream_willservice(stp);
58840Sstevel@tonic-gate 	putnext(stp->sd_wrq, bp);
58850Sstevel@tonic-gate 	stream_runservice(stp);
58860Sstevel@tonic-gate 
58870Sstevel@tonic-gate 	/*
58880Sstevel@tonic-gate 	 * Timed wait for acknowledgment.  The wait time is limited by the
58890Sstevel@tonic-gate 	 * timeout value, which must be a positive integer (number of
5890*898Skais 	 * milliseconds) to wait, or 0 (use default value of STRTIMOUT
58910Sstevel@tonic-gate 	 * milliseconds), or -1 (wait forever).  This will be awakened
58920Sstevel@tonic-gate 	 * either by an ACK/NAK message arriving, the timer expiring, or
58930Sstevel@tonic-gate 	 * the timer expiring on another ioctl waiting for control of the
58940Sstevel@tonic-gate 	 * mechanism.
58950Sstevel@tonic-gate 	 */
58960Sstevel@tonic-gate waitioc:
58970Sstevel@tonic-gate 	mutex_enter(&stp->sd_lock);
58980Sstevel@tonic-gate 
58990Sstevel@tonic-gate 
59000Sstevel@tonic-gate 	/*
59010Sstevel@tonic-gate 	 * If the reply has already arrived, don't sleep.  If awakened from
59020Sstevel@tonic-gate 	 * the sleep, fail only if the reply has not arrived by then.
59030Sstevel@tonic-gate 	 * Otherwise, process the reply.
59040Sstevel@tonic-gate 	 */
59050Sstevel@tonic-gate 	while (!stp->sd_iocblk) {
59060Sstevel@tonic-gate 		clock_t cv_rval;
59070Sstevel@tonic-gate 
59080Sstevel@tonic-gate 		if (stp->sd_flag & errs) {
59090Sstevel@tonic-gate 			error = strgeterr(stp, errs, 0);
59100Sstevel@tonic-gate 			if (error != 0) {
59110Sstevel@tonic-gate 				stp->sd_flag &= ~waitflags;
59120Sstevel@tonic-gate 				cv_broadcast(&stp->sd_iocmonitor);
59130Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
59140Sstevel@tonic-gate 				crfree(crp);
59150Sstevel@tonic-gate 				return (error);
59160Sstevel@tonic-gate 			}
59170Sstevel@tonic-gate 		}
59180Sstevel@tonic-gate 
59190Sstevel@tonic-gate 		TRACE_0(TR_FAC_STREAMS_FR,
59200Sstevel@tonic-gate 			TR_STRDOIOCTL_WAIT2,
59210Sstevel@tonic-gate 			"strdoioctl sleeps awaiting reply");
59220Sstevel@tonic-gate 		ASSERT(error == 0);
59230Sstevel@tonic-gate 
59240Sstevel@tonic-gate 		cv_rval = str_cv_wait(&stp->sd_monitor, &stp->sd_lock,
59250Sstevel@tonic-gate 		    (strioc->ic_timout ?
59260Sstevel@tonic-gate 		    strioc->ic_timout * 1000 : STRTIMOUT), sigflag);
59270Sstevel@tonic-gate 
59280Sstevel@tonic-gate 		/*
59290Sstevel@tonic-gate 		 * There are four possible cases here: interrupt, timeout,
59300Sstevel@tonic-gate 		 * wakeup by IOCWAITNE (above), or wakeup by strrput_nondata (a
59310Sstevel@tonic-gate 		 * valid M_IOCTL reply).
59320Sstevel@tonic-gate 		 *
59330Sstevel@tonic-gate 		 * If we've been awakened by a STR_NOERROR ioctl on some other
59340Sstevel@tonic-gate 		 * thread, then sd_iocblk will still be NULL, and IOCWAITNE
59350Sstevel@tonic-gate 		 * will be set.  Pretend as if we just timed out.  Note that
59360Sstevel@tonic-gate 		 * this other thread waited at least STRTIMOUT before trying to
59370Sstevel@tonic-gate 		 * awaken our thread, so this is indistinguishable (even for
59380Sstevel@tonic-gate 		 * INFTIM) from the case where we failed with ETIME waiting on
59390Sstevel@tonic-gate 		 * IOCWAIT in the prior loop.
59400Sstevel@tonic-gate 		 */
59410Sstevel@tonic-gate 		if (cv_rval > 0 && !(flag & STR_NOERROR) &&
59420Sstevel@tonic-gate 		    stp->sd_iocblk == NULL && (stp->sd_flag & IOCWAITNE)) {
59430Sstevel@tonic-gate 			cv_rval = -1;
59440Sstevel@tonic-gate 		}
59450Sstevel@tonic-gate 
59460Sstevel@tonic-gate 		/*
59470Sstevel@tonic-gate 		 * note: STR_NOERROR does not protect
59480Sstevel@tonic-gate 		 * us here.. use ic_timout < 0
59490Sstevel@tonic-gate 		 */
59500Sstevel@tonic-gate 		if (cv_rval <= 0) {
59510Sstevel@tonic-gate 			if (cv_rval == 0) {
59520Sstevel@tonic-gate 				error = EINTR;
59530Sstevel@tonic-gate 			} else {
59540Sstevel@tonic-gate 				error =  ETIME;
59550Sstevel@tonic-gate 			}
59560Sstevel@tonic-gate 			/*
59570Sstevel@tonic-gate 			 * A message could have come in after we were scheduled
59580Sstevel@tonic-gate 			 * but before we were actually run.
59590Sstevel@tonic-gate 			 */
59600Sstevel@tonic-gate 			bp = stp->sd_iocblk;
59610Sstevel@tonic-gate 			stp->sd_iocblk = NULL;
59620Sstevel@tonic-gate 			if (bp != NULL) {
59630Sstevel@tonic-gate 				if ((bp->b_datap->db_type == M_COPYIN) ||
59640Sstevel@tonic-gate 				    (bp->b_datap->db_type == M_COPYOUT)) {
59650Sstevel@tonic-gate 					mutex_exit(&stp->sd_lock);
59660Sstevel@tonic-gate 					if (bp->b_cont) {
59670Sstevel@tonic-gate 						freemsg(bp->b_cont);
59680Sstevel@tonic-gate 						bp->b_cont = NULL;
59690Sstevel@tonic-gate 					}
59700Sstevel@tonic-gate 					bp->b_datap->db_type = M_IOCDATA;
59710Sstevel@tonic-gate 					bp->b_wptr = bp->b_rptr +
59720Sstevel@tonic-gate 						sizeof (struct copyresp);
59730Sstevel@tonic-gate 					resp = (struct copyresp *)bp->b_rptr;
59740Sstevel@tonic-gate 					resp->cp_rval =
59750Sstevel@tonic-gate 					    (caddr_t)1; /* failure */
59760Sstevel@tonic-gate 					stream_willservice(stp);
59770Sstevel@tonic-gate 					putnext(stp->sd_wrq, bp);
59780Sstevel@tonic-gate 					stream_runservice(stp);
59790Sstevel@tonic-gate 					mutex_enter(&stp->sd_lock);
59800Sstevel@tonic-gate 				} else {
59810Sstevel@tonic-gate 					freemsg(bp);
59820Sstevel@tonic-gate 				}
59830Sstevel@tonic-gate 			}
59840Sstevel@tonic-gate 			stp->sd_flag &= ~waitflags;
59850Sstevel@tonic-gate 			cv_broadcast(&stp->sd_iocmonitor);
59860Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
59870Sstevel@tonic-gate 			crfree(crp);
59880Sstevel@tonic-gate 			return (error);
59890Sstevel@tonic-gate 		}
59900Sstevel@tonic-gate 	}
59910Sstevel@tonic-gate 	bp = stp->sd_iocblk;
59920Sstevel@tonic-gate 	/*
59930Sstevel@tonic-gate 	 * Note: it is strictly impossible to get here with sd_iocblk set to
59940Sstevel@tonic-gate 	 * -1.  This is because the initial loop above doesn't allow any new
59950Sstevel@tonic-gate 	 * ioctls into the fray until all others have passed this point.
59960Sstevel@tonic-gate 	 */
59970Sstevel@tonic-gate 	ASSERT(bp != NULL && bp != (mblk_t *)-1);
59980Sstevel@tonic-gate 	TRACE_1(TR_FAC_STREAMS_FR,
59990Sstevel@tonic-gate 		TR_STRDOIOCTL_ACK, "strdoioctl got reply: bp %p", bp);
60000Sstevel@tonic-gate 	if ((bp->b_datap->db_type == M_IOCACK) ||
60010Sstevel@tonic-gate 	    (bp->b_datap->db_type == M_IOCNAK)) {
60020Sstevel@tonic-gate 		/* for detection of duplicate ioctl replies */
60030Sstevel@tonic-gate 		stp->sd_iocblk = (mblk_t *)-1;
60040Sstevel@tonic-gate 		stp->sd_flag &= ~waitflags;
60050Sstevel@tonic-gate 		cv_broadcast(&stp->sd_iocmonitor);
60060Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
60070Sstevel@tonic-gate 	} else {
60080Sstevel@tonic-gate 		/*
60090Sstevel@tonic-gate 		 * flags not cleared here because we're still doing
60100Sstevel@tonic-gate 		 * copy in/out for ioctl.
60110Sstevel@tonic-gate 		 */
60120Sstevel@tonic-gate 		stp->sd_iocblk = NULL;
60130Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
60140Sstevel@tonic-gate 	}
60150Sstevel@tonic-gate 
60160Sstevel@tonic-gate 
60170Sstevel@tonic-gate 	/*
60180Sstevel@tonic-gate 	 * Have received acknowledgment.
60190Sstevel@tonic-gate 	 */
60200Sstevel@tonic-gate 
60210Sstevel@tonic-gate 	switch (bp->b_datap->db_type) {
60220Sstevel@tonic-gate 	case M_IOCACK:
60230Sstevel@tonic-gate 		/*
60240Sstevel@tonic-gate 		 * Positive ack.
60250Sstevel@tonic-gate 		 */
60260Sstevel@tonic-gate 		iocbp = (struct iocblk *)bp->b_rptr;
60270Sstevel@tonic-gate 
60280Sstevel@tonic-gate 		/*
60290Sstevel@tonic-gate 		 * Set error if indicated.
60300Sstevel@tonic-gate 		 */
60310Sstevel@tonic-gate 		if (iocbp->ioc_error) {
60320Sstevel@tonic-gate 			error = iocbp->ioc_error;
60330Sstevel@tonic-gate 			break;
60340Sstevel@tonic-gate 		}
60350Sstevel@tonic-gate 
60360Sstevel@tonic-gate 		/*
60370Sstevel@tonic-gate 		 * Set return value.
60380Sstevel@tonic-gate 		 */
60390Sstevel@tonic-gate 		*rvalp = iocbp->ioc_rval;
60400Sstevel@tonic-gate 
60410Sstevel@tonic-gate 		/*
60420Sstevel@tonic-gate 		 * Data may have been returned in ACK message (ioc_count > 0).
60430Sstevel@tonic-gate 		 * If so, copy it out to the user's buffer.
60440Sstevel@tonic-gate 		 */
60450Sstevel@tonic-gate 		if (iocbp->ioc_count && !transparent) {
60460Sstevel@tonic-gate 			if (error = getiocd(bp, strioc->ic_dp, copyflag))
60470Sstevel@tonic-gate 				break;
60480Sstevel@tonic-gate 		}
60490Sstevel@tonic-gate 		if (!transparent) {
60500Sstevel@tonic-gate 			if (len)	/* an M_COPYOUT was used with I_STR */
60510Sstevel@tonic-gate 				strioc->ic_len = len;
60520Sstevel@tonic-gate 			else
60530Sstevel@tonic-gate 				strioc->ic_len = (int)iocbp->ioc_count;
60540Sstevel@tonic-gate 		}
60550Sstevel@tonic-gate 		break;
60560Sstevel@tonic-gate 
60570Sstevel@tonic-gate 	case M_IOCNAK:
60580Sstevel@tonic-gate 		/*
60590Sstevel@tonic-gate 		 * Negative ack.
60600Sstevel@tonic-gate 		 *
60610Sstevel@tonic-gate 		 * The only thing to do is set error as specified
60620Sstevel@tonic-gate 		 * in neg ack packet.
60630Sstevel@tonic-gate 		 */
60640Sstevel@tonic-gate 		iocbp = (struct iocblk *)bp->b_rptr;
60650Sstevel@tonic-gate 
60660Sstevel@tonic-gate 		error = (iocbp->ioc_error ? iocbp->ioc_error : EINVAL);
60670Sstevel@tonic-gate 		break;
60680Sstevel@tonic-gate 
60690Sstevel@tonic-gate 	case M_COPYIN:
60700Sstevel@tonic-gate 		/*
60710Sstevel@tonic-gate 		 * Driver or module has requested user ioctl data.
60720Sstevel@tonic-gate 		 */
60730Sstevel@tonic-gate 		reqp = (struct copyreq *)bp->b_rptr;
60740Sstevel@tonic-gate 
60750Sstevel@tonic-gate 		/*
60760Sstevel@tonic-gate 		 * M_COPYIN should *never* have a message attached, though
60770Sstevel@tonic-gate 		 * it's harmless if it does -- thus, panic on a DEBUG
60780Sstevel@tonic-gate 		 * kernel and just free it on a non-DEBUG build.
60790Sstevel@tonic-gate 		 */
60800Sstevel@tonic-gate 		ASSERT(bp->b_cont == NULL);
60810Sstevel@tonic-gate 		if (bp->b_cont != NULL) {
60820Sstevel@tonic-gate 			freemsg(bp->b_cont);
60830Sstevel@tonic-gate 			bp->b_cont = NULL;
60840Sstevel@tonic-gate 		}
60850Sstevel@tonic-gate 
60860Sstevel@tonic-gate 		error = putiocd(bp, reqp->cq_addr, flag, crp);
60870Sstevel@tonic-gate 		if (error && bp->b_cont) {
60880Sstevel@tonic-gate 			freemsg(bp->b_cont);
60890Sstevel@tonic-gate 			bp->b_cont = NULL;
60900Sstevel@tonic-gate 		}
60910Sstevel@tonic-gate 
60920Sstevel@tonic-gate 		bp->b_wptr = bp->b_rptr + sizeof (struct copyresp);
60930Sstevel@tonic-gate 		bp->b_datap->db_type = M_IOCDATA;
60940Sstevel@tonic-gate 
60950Sstevel@tonic-gate 		mblk_setcred(bp, crp);
60960Sstevel@tonic-gate 		DB_CPID(bp) = curproc->p_pid;
60970Sstevel@tonic-gate 		resp = (struct copyresp *)bp->b_rptr;
60980Sstevel@tonic-gate 		resp->cp_rval = (caddr_t)(uintptr_t)error;
60990Sstevel@tonic-gate 		resp->cp_flag = (fflags & FMODELS);
61000Sstevel@tonic-gate 
61010Sstevel@tonic-gate 		stream_willservice(stp);
61020Sstevel@tonic-gate 		putnext(stp->sd_wrq, bp);
61030Sstevel@tonic-gate 		stream_runservice(stp);
61040Sstevel@tonic-gate 
61050Sstevel@tonic-gate 		if (error) {
61060Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
61070Sstevel@tonic-gate 			stp->sd_flag &= ~waitflags;
61080Sstevel@tonic-gate 			cv_broadcast(&stp->sd_iocmonitor);
61090Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
61100Sstevel@tonic-gate 			crfree(crp);
61110Sstevel@tonic-gate 			return (error);
61120Sstevel@tonic-gate 		}
61130Sstevel@tonic-gate 
61140Sstevel@tonic-gate 		goto waitioc;
61150Sstevel@tonic-gate 
61160Sstevel@tonic-gate 	case M_COPYOUT:
61170Sstevel@tonic-gate 		/*
61180Sstevel@tonic-gate 		 * Driver or module has ioctl data for a user.
61190Sstevel@tonic-gate 		 */
61200Sstevel@tonic-gate 		reqp = (struct copyreq *)bp->b_rptr;
61210Sstevel@tonic-gate 		ASSERT(bp->b_cont != NULL);
61220Sstevel@tonic-gate 
61230Sstevel@tonic-gate 		/*
61240Sstevel@tonic-gate 		 * Always (transparent or non-transparent )
61250Sstevel@tonic-gate 		 * use the address specified in the request
61260Sstevel@tonic-gate 		 */
61270Sstevel@tonic-gate 		taddr = reqp->cq_addr;
61280Sstevel@tonic-gate 		if (!transparent)
61290Sstevel@tonic-gate 			len = (int)reqp->cq_size;
61300Sstevel@tonic-gate 
61310Sstevel@tonic-gate 		/* copyout data to the provided address */
61320Sstevel@tonic-gate 		error = getiocd(bp, taddr, copyflag);
61330Sstevel@tonic-gate 
61340Sstevel@tonic-gate 		freemsg(bp->b_cont);
61350Sstevel@tonic-gate 		bp->b_cont = NULL;
61360Sstevel@tonic-gate 
61370Sstevel@tonic-gate 		bp->b_wptr = bp->b_rptr + sizeof (struct copyresp);
61380Sstevel@tonic-gate 		bp->b_datap->db_type = M_IOCDATA;
61390Sstevel@tonic-gate 
61400Sstevel@tonic-gate 		mblk_setcred(bp, crp);
61410Sstevel@tonic-gate 		DB_CPID(bp) = curproc->p_pid;
61420Sstevel@tonic-gate 		resp = (struct copyresp *)bp->b_rptr;
61430Sstevel@tonic-gate 		resp->cp_rval = (caddr_t)(uintptr_t)error;
61440Sstevel@tonic-gate 		resp->cp_flag = (fflags & FMODELS);
61450Sstevel@tonic-gate 
61460Sstevel@tonic-gate 		stream_willservice(stp);
61470Sstevel@tonic-gate 		putnext(stp->sd_wrq, bp);
61480Sstevel@tonic-gate 		stream_runservice(stp);
61490Sstevel@tonic-gate 
61500Sstevel@tonic-gate 		if (error) {
61510Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
61520Sstevel@tonic-gate 			stp->sd_flag &= ~waitflags;
61530Sstevel@tonic-gate 			cv_broadcast(&stp->sd_iocmonitor);
61540Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
61550Sstevel@tonic-gate 			crfree(crp);
61560Sstevel@tonic-gate 			return (error);
61570Sstevel@tonic-gate 		}
61580Sstevel@tonic-gate 		goto waitioc;
61590Sstevel@tonic-gate 
61600Sstevel@tonic-gate 	default:
61610Sstevel@tonic-gate 		ASSERT(0);
61620Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
61630Sstevel@tonic-gate 		stp->sd_flag &= ~waitflags;
61640Sstevel@tonic-gate 		cv_broadcast(&stp->sd_iocmonitor);
61650Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
61660Sstevel@tonic-gate 		break;
61670Sstevel@tonic-gate 	}
61680Sstevel@tonic-gate 
61690Sstevel@tonic-gate 	freemsg(bp);
61700Sstevel@tonic-gate 	crfree(crp);
61710Sstevel@tonic-gate 	return (error);
61720Sstevel@tonic-gate }
61730Sstevel@tonic-gate 
61740Sstevel@tonic-gate /*
61750Sstevel@tonic-gate  * For the SunOS keyboard driver.
61760Sstevel@tonic-gate  * Return the next available "ioctl" sequence number.
61770Sstevel@tonic-gate  * Exported, so that streams modules can send "ioctl" messages
61780Sstevel@tonic-gate  * downstream from their open routine.
61790Sstevel@tonic-gate  */
61800Sstevel@tonic-gate int
61810Sstevel@tonic-gate getiocseqno(void)
61820Sstevel@tonic-gate {
61830Sstevel@tonic-gate 	int	i;
61840Sstevel@tonic-gate 
61850Sstevel@tonic-gate 	mutex_enter(&strresources);
61860Sstevel@tonic-gate 	i = ++ioc_id;
61870Sstevel@tonic-gate 	mutex_exit(&strresources);
61880Sstevel@tonic-gate 	return (i);
61890Sstevel@tonic-gate }
61900Sstevel@tonic-gate 
61910Sstevel@tonic-gate /*
61920Sstevel@tonic-gate  * Get the next message from the read queue.  If the message is
61930Sstevel@tonic-gate  * priority, STRPRI will have been set by strrput().  This flag
61940Sstevel@tonic-gate  * should be reset only when the entire message at the front of the
61950Sstevel@tonic-gate  * queue as been consumed.
61960Sstevel@tonic-gate  *
61970Sstevel@tonic-gate  * NOTE: strgetmsg and kstrgetmsg have much of the logic in common.
61980Sstevel@tonic-gate  */
61990Sstevel@tonic-gate int
62000Sstevel@tonic-gate strgetmsg(
62010Sstevel@tonic-gate 	struct vnode *vp,
62020Sstevel@tonic-gate 	struct strbuf *mctl,
62030Sstevel@tonic-gate 	struct strbuf *mdata,
62040Sstevel@tonic-gate 	unsigned char *prip,
62050Sstevel@tonic-gate 	int *flagsp,
62060Sstevel@tonic-gate 	int fmode,
62070Sstevel@tonic-gate 	rval_t *rvp)
62080Sstevel@tonic-gate {
62090Sstevel@tonic-gate 	struct stdata *stp;
62100Sstevel@tonic-gate 	mblk_t *bp, *nbp;
62110Sstevel@tonic-gate 	mblk_t *savemp = NULL;
62120Sstevel@tonic-gate 	mblk_t *savemptail = NULL;
62130Sstevel@tonic-gate 	uint_t old_sd_flag;
62140Sstevel@tonic-gate 	int flg;
62150Sstevel@tonic-gate 	int more = 0;
62160Sstevel@tonic-gate 	int error = 0;
62170Sstevel@tonic-gate 	char first = 1;
62180Sstevel@tonic-gate 	uint_t mark;		/* Contains MSG*MARK and _LASTMARK */
62190Sstevel@tonic-gate #define	_LASTMARK	0x8000	/* Distinct from MSG*MARK */
62200Sstevel@tonic-gate 	unsigned char pri = 0;
62210Sstevel@tonic-gate 	queue_t *q;
62220Sstevel@tonic-gate 	int	pr = 0;			/* Partial read successful */
62230Sstevel@tonic-gate 	struct uio uios;
62240Sstevel@tonic-gate 	struct uio *uiop = &uios;
62250Sstevel@tonic-gate 	struct iovec iovs;
62260Sstevel@tonic-gate 	unsigned char type;
62270Sstevel@tonic-gate 
62280Sstevel@tonic-gate 	TRACE_1(TR_FAC_STREAMS_FR, TR_STRGETMSG_ENTER,
62290Sstevel@tonic-gate 		"strgetmsg:%p", vp);
62300Sstevel@tonic-gate 
62310Sstevel@tonic-gate 	ASSERT(vp->v_stream);
62320Sstevel@tonic-gate 	stp = vp->v_stream;
62330Sstevel@tonic-gate 	rvp->r_val1 = 0;
62340Sstevel@tonic-gate 
62350Sstevel@tonic-gate 	if (stp->sd_sidp != NULL && stp->sd_vnode->v_type != VFIFO)
62360Sstevel@tonic-gate 		if (error = straccess(stp, JCREAD))
62370Sstevel@tonic-gate 			return (error);
62380Sstevel@tonic-gate 
62390Sstevel@tonic-gate 	/* Fast check of flags before acquiring the lock */
62400Sstevel@tonic-gate 	if (stp->sd_flag & (STRDERR|STPLEX)) {
62410Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
62420Sstevel@tonic-gate 		error = strgeterr(stp, STRDERR|STPLEX, 0);
62430Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
62440Sstevel@tonic-gate 		if (error != 0)
62450Sstevel@tonic-gate 			return (error);
62460Sstevel@tonic-gate 	}
62470Sstevel@tonic-gate 
62480Sstevel@tonic-gate 	switch (*flagsp) {
62490Sstevel@tonic-gate 	case MSG_HIPRI:
62500Sstevel@tonic-gate 		if (*prip != 0)
62510Sstevel@tonic-gate 			return (EINVAL);
62520Sstevel@tonic-gate 		break;
62530Sstevel@tonic-gate 
62540Sstevel@tonic-gate 	case MSG_ANY:
62550Sstevel@tonic-gate 	case MSG_BAND:
62560Sstevel@tonic-gate 		break;
62570Sstevel@tonic-gate 
62580Sstevel@tonic-gate 	default:
62590Sstevel@tonic-gate 		return (EINVAL);
62600Sstevel@tonic-gate 	}
62610Sstevel@tonic-gate 	/*
62620Sstevel@tonic-gate 	 * Setup uio and iov for data part
62630Sstevel@tonic-gate 	 */
62640Sstevel@tonic-gate 	iovs.iov_base = mdata->buf;
62650Sstevel@tonic-gate 	iovs.iov_len = mdata->maxlen;
62660Sstevel@tonic-gate 	uios.uio_iov = &iovs;
62670Sstevel@tonic-gate 	uios.uio_iovcnt = 1;
62680Sstevel@tonic-gate 	uios.uio_loffset = 0;
62690Sstevel@tonic-gate 	uios.uio_segflg = UIO_USERSPACE;
62700Sstevel@tonic-gate 	uios.uio_fmode = 0;
62710Sstevel@tonic-gate 	uios.uio_extflg = UIO_COPY_CACHED;
62720Sstevel@tonic-gate 	uios.uio_resid = mdata->maxlen;
62730Sstevel@tonic-gate 	uios.uio_offset = 0;
62740Sstevel@tonic-gate 
62750Sstevel@tonic-gate 	q = _RD(stp->sd_wrq);
62760Sstevel@tonic-gate 	mutex_enter(&stp->sd_lock);
62770Sstevel@tonic-gate 	old_sd_flag = stp->sd_flag;
62780Sstevel@tonic-gate 	mark = 0;
62790Sstevel@tonic-gate 	for (;;) {
62800Sstevel@tonic-gate 		int done = 0;
62810Sstevel@tonic-gate 		mblk_t *q_first = q->q_first;
62820Sstevel@tonic-gate 
62830Sstevel@tonic-gate 		/*
62840Sstevel@tonic-gate 		 * Get the next message of appropriate priority
62850Sstevel@tonic-gate 		 * from the stream head.  If the caller is interested
62860Sstevel@tonic-gate 		 * in band or hipri messages, then they should already
62870Sstevel@tonic-gate 		 * be enqueued at the stream head.  On the other hand
62880Sstevel@tonic-gate 		 * if the caller wants normal (band 0) messages, they
62890Sstevel@tonic-gate 		 * might be deferred in a synchronous stream and they
62900Sstevel@tonic-gate 		 * will need to be pulled up.
62910Sstevel@tonic-gate 		 *
62920Sstevel@tonic-gate 		 * After we have dequeued a message, we might find that
62930Sstevel@tonic-gate 		 * it was a deferred M_SIG that was enqueued at the
62940Sstevel@tonic-gate 		 * stream head.  It must now be posted as part of the
62950Sstevel@tonic-gate 		 * read by calling strsignal_nolock().
62960Sstevel@tonic-gate 		 *
62970Sstevel@tonic-gate 		 * Also note that strrput does not enqueue an M_PCSIG,
62980Sstevel@tonic-gate 		 * and there cannot be more than one hipri message,
62990Sstevel@tonic-gate 		 * so there was no need to have the M_PCSIG case.
63000Sstevel@tonic-gate 		 *
63010Sstevel@tonic-gate 		 * At some time it might be nice to try and wrap the
63020Sstevel@tonic-gate 		 * functionality of kstrgetmsg() and strgetmsg() into
63030Sstevel@tonic-gate 		 * a common routine so to reduce the amount of replicated
63040Sstevel@tonic-gate 		 * code (since they are extremely similar).
63050Sstevel@tonic-gate 		 */
63060Sstevel@tonic-gate 		if (!(*flagsp & (MSG_HIPRI|MSG_BAND))) {
63070Sstevel@tonic-gate 			/* Asking for normal, band0 data */
63080Sstevel@tonic-gate 			bp = strget(stp, q, uiop, first, &error);
63090Sstevel@tonic-gate 			ASSERT(MUTEX_HELD(&stp->sd_lock));
63100Sstevel@tonic-gate 			if (bp != NULL) {
63110Sstevel@tonic-gate 				if (bp->b_datap->db_type == M_SIG) {
63120Sstevel@tonic-gate 					strsignal_nolock(stp, *bp->b_rptr,
63130Sstevel@tonic-gate 					    (int32_t)bp->b_band);
63140Sstevel@tonic-gate 					continue;
63150Sstevel@tonic-gate 				} else {
63160Sstevel@tonic-gate 					break;
63170Sstevel@tonic-gate 				}
63180Sstevel@tonic-gate 			}
63190Sstevel@tonic-gate 			if (error != 0) {
63200Sstevel@tonic-gate 				goto getmout;
63210Sstevel@tonic-gate 			}
63220Sstevel@tonic-gate 
63230Sstevel@tonic-gate 		/*
63240Sstevel@tonic-gate 		 * We can't depend on the value of STRPRI here because
63250Sstevel@tonic-gate 		 * the stream head may be in transit. Therefore, we
63260Sstevel@tonic-gate 		 * must look at the type of the first message to
63270Sstevel@tonic-gate 		 * determine if a high priority messages is waiting
63280Sstevel@tonic-gate 		 */
63290Sstevel@tonic-gate 		} else if ((*flagsp & MSG_HIPRI) && q_first != NULL &&
63300Sstevel@tonic-gate 			    q_first->b_datap->db_type >= QPCTL &&
63310Sstevel@tonic-gate 			    (bp = getq_noenab(q)) != NULL) {
63320Sstevel@tonic-gate 			/* Asked for HIPRI and got one */
63330Sstevel@tonic-gate 			ASSERT(bp->b_datap->db_type >= QPCTL);
63340Sstevel@tonic-gate 			break;
63350Sstevel@tonic-gate 		} else if ((*flagsp & MSG_BAND) && q_first != NULL &&
63360Sstevel@tonic-gate 			    ((q_first->b_band >= *prip) ||
63370Sstevel@tonic-gate 			    q_first->b_datap->db_type >= QPCTL) &&
63380Sstevel@tonic-gate 			    (bp = getq_noenab(q)) != NULL) {
63390Sstevel@tonic-gate 			/*
63400Sstevel@tonic-gate 			 * Asked for at least band "prip" and got either at
63410Sstevel@tonic-gate 			 * least that band or a hipri message.
63420Sstevel@tonic-gate 			 */
63430Sstevel@tonic-gate 			ASSERT(bp->b_band >= *prip ||
63440Sstevel@tonic-gate 				bp->b_datap->db_type >= QPCTL);
63450Sstevel@tonic-gate 			if (bp->b_datap->db_type == M_SIG) {
63460Sstevel@tonic-gate 				strsignal_nolock(stp, *bp->b_rptr,
63470Sstevel@tonic-gate 				    (int32_t)bp->b_band);
63480Sstevel@tonic-gate 				continue;
63490Sstevel@tonic-gate 			} else {
63500Sstevel@tonic-gate 				break;
63510Sstevel@tonic-gate 			}
63520Sstevel@tonic-gate 		}
63530Sstevel@tonic-gate 
63540Sstevel@tonic-gate 		/* No data. Time to sleep? */
63550Sstevel@tonic-gate 		qbackenable(q, 0);
63560Sstevel@tonic-gate 
63570Sstevel@tonic-gate 		/*
63580Sstevel@tonic-gate 		 * If STRHUP or STREOF, return 0 length control and data.
63590Sstevel@tonic-gate 		 * If resid is 0, then a read(fd,buf,0) was done. Do not
63600Sstevel@tonic-gate 		 * sleep to satisfy this request because by default we have
63610Sstevel@tonic-gate 		 * zero bytes to return.
63620Sstevel@tonic-gate 		 */
63630Sstevel@tonic-gate 		if ((stp->sd_flag & (STRHUP|STREOF)) || (mctl->maxlen == 0 &&
63640Sstevel@tonic-gate 		    mdata->maxlen == 0)) {
63650Sstevel@tonic-gate 			mctl->len = mdata->len = 0;
63660Sstevel@tonic-gate 			*flagsp = 0;
63670Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
63680Sstevel@tonic-gate 			return (0);
63690Sstevel@tonic-gate 		}
63700Sstevel@tonic-gate 		TRACE_2(TR_FAC_STREAMS_FR, TR_STRGETMSG_WAIT,
63710Sstevel@tonic-gate 			"strgetmsg calls strwaitq:%p, %p",
63720Sstevel@tonic-gate 			vp, uiop);
63730Sstevel@tonic-gate 		if (((error = strwaitq(stp, GETWAIT, (ssize_t)0, fmode, -1,
63740Sstevel@tonic-gate 		    &done)) != 0) || done) {
63750Sstevel@tonic-gate 			TRACE_2(TR_FAC_STREAMS_FR, TR_STRGETMSG_DONE,
63760Sstevel@tonic-gate 				"strgetmsg error or done:%p, %p",
63770Sstevel@tonic-gate 				vp, uiop);
63780Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
63790Sstevel@tonic-gate 			return (error);
63800Sstevel@tonic-gate 		}
63810Sstevel@tonic-gate 		TRACE_2(TR_FAC_STREAMS_FR, TR_STRGETMSG_AWAKE,
63820Sstevel@tonic-gate 			"strgetmsg awakes:%p, %p", vp, uiop);
63830Sstevel@tonic-gate 		if (stp->sd_sidp != NULL && stp->sd_vnode->v_type != VFIFO) {
63840Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
63850Sstevel@tonic-gate 			if (error = straccess(stp, JCREAD))
63860Sstevel@tonic-gate 				return (error);
63870Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
63880Sstevel@tonic-gate 		}
63890Sstevel@tonic-gate 		first = 0;
63900Sstevel@tonic-gate 	}
63910Sstevel@tonic-gate 	ASSERT(bp != NULL);
63920Sstevel@tonic-gate 	/*
63930Sstevel@tonic-gate 	 * Extract any mark information. If the message is not completely
63940Sstevel@tonic-gate 	 * consumed this information will be put in the mblk
63950Sstevel@tonic-gate 	 * that is putback.
63960Sstevel@tonic-gate 	 * If MSGMARKNEXT is set and the message is completely consumed
63970Sstevel@tonic-gate 	 * the STRATMARK flag will be set below. Likewise, if
63980Sstevel@tonic-gate 	 * MSGNOTMARKNEXT is set and the message is
63990Sstevel@tonic-gate 	 * completely consumed STRNOTATMARK will be set.
64000Sstevel@tonic-gate 	 */
64010Sstevel@tonic-gate 	mark = bp->b_flag & (MSGMARK | MSGMARKNEXT | MSGNOTMARKNEXT);
64020Sstevel@tonic-gate 	ASSERT((mark & (MSGMARKNEXT|MSGNOTMARKNEXT)) !=
64030Sstevel@tonic-gate 		(MSGMARKNEXT|MSGNOTMARKNEXT));
64040Sstevel@tonic-gate 	if (mark != 0 && bp == stp->sd_mark) {
64050Sstevel@tonic-gate 		mark |= _LASTMARK;
64060Sstevel@tonic-gate 		stp->sd_mark = NULL;
64070Sstevel@tonic-gate 	}
64080Sstevel@tonic-gate 	/*
64090Sstevel@tonic-gate 	 * keep track of the original message type and priority
64100Sstevel@tonic-gate 	 */
64110Sstevel@tonic-gate 	pri = bp->b_band;
64120Sstevel@tonic-gate 	type = bp->b_datap->db_type;
64130Sstevel@tonic-gate 	if (type == M_PASSFP) {
64140Sstevel@tonic-gate 		if ((mark & _LASTMARK) && (stp->sd_mark == NULL))
64150Sstevel@tonic-gate 			stp->sd_mark = bp;
64160Sstevel@tonic-gate 		bp->b_flag |= mark & ~_LASTMARK;
64170Sstevel@tonic-gate 		putback(stp, q, bp, pri);
64180Sstevel@tonic-gate 		qbackenable(q, pri);
64190Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
64200Sstevel@tonic-gate 		return (EBADMSG);
64210Sstevel@tonic-gate 	}
64220Sstevel@tonic-gate 	ASSERT(type != M_SIG);
64230Sstevel@tonic-gate 
64240Sstevel@tonic-gate 	/*
64250Sstevel@tonic-gate 	 * Set this flag so strrput will not generate signals. Need to
64260Sstevel@tonic-gate 	 * make sure this flag is cleared before leaving this routine
64270Sstevel@tonic-gate 	 * else signals will stop being sent.
64280Sstevel@tonic-gate 	 */
64290Sstevel@tonic-gate 	stp->sd_flag |= STRGETINPROG;
64300Sstevel@tonic-gate 	mutex_exit(&stp->sd_lock);
64310Sstevel@tonic-gate 
64320Sstevel@tonic-gate 	if (STREAM_NEEDSERVICE(stp))
64330Sstevel@tonic-gate 		stream_runservice(stp);
64340Sstevel@tonic-gate 
64350Sstevel@tonic-gate 	/*
64360Sstevel@tonic-gate 	 * Set HIPRI flag if message is priority.
64370Sstevel@tonic-gate 	 */
64380Sstevel@tonic-gate 	if (type >= QPCTL)
64390Sstevel@tonic-gate 		flg = MSG_HIPRI;
64400Sstevel@tonic-gate 	else
64410Sstevel@tonic-gate 		flg = MSG_BAND;
64420Sstevel@tonic-gate 
64430Sstevel@tonic-gate 	/*
64440Sstevel@tonic-gate 	 * First process PROTO or PCPROTO blocks, if any.
64450Sstevel@tonic-gate 	 */
64460Sstevel@tonic-gate 	if (mctl->maxlen >= 0 && type != M_DATA) {
64470Sstevel@tonic-gate 		size_t	n, bcnt;
64480Sstevel@tonic-gate 		char	*ubuf;
64490Sstevel@tonic-gate 
64500Sstevel@tonic-gate 		bcnt = mctl->maxlen;
64510Sstevel@tonic-gate 		ubuf = mctl->buf;
64520Sstevel@tonic-gate 		while (bp != NULL && bp->b_datap->db_type != M_DATA) {
64530Sstevel@tonic-gate 			if ((n = MIN(bcnt, bp->b_wptr - bp->b_rptr)) != 0 &&
64540Sstevel@tonic-gate 			    copyout(bp->b_rptr, ubuf, n)) {
64550Sstevel@tonic-gate 				error = EFAULT;
64560Sstevel@tonic-gate 				mutex_enter(&stp->sd_lock);
64570Sstevel@tonic-gate 				/*
64580Sstevel@tonic-gate 				 * clear stream head pri flag based on
64590Sstevel@tonic-gate 				 * first message type
64600Sstevel@tonic-gate 				 */
64610Sstevel@tonic-gate 				if (type >= QPCTL) {
64620Sstevel@tonic-gate 					ASSERT(type == M_PCPROTO);
64630Sstevel@tonic-gate 					stp->sd_flag &= ~STRPRI;
64640Sstevel@tonic-gate 				}
64650Sstevel@tonic-gate 				more = 0;
64660Sstevel@tonic-gate 				freemsg(bp);
64670Sstevel@tonic-gate 				goto getmout;
64680Sstevel@tonic-gate 			}
64690Sstevel@tonic-gate 			ubuf += n;
64700Sstevel@tonic-gate 			bp->b_rptr += n;
64710Sstevel@tonic-gate 			if (bp->b_rptr >= bp->b_wptr) {
64720Sstevel@tonic-gate 				nbp = bp;
64730Sstevel@tonic-gate 				bp = bp->b_cont;
64740Sstevel@tonic-gate 				freeb(nbp);
64750Sstevel@tonic-gate 			}
64760Sstevel@tonic-gate 			ASSERT(n <= bcnt);
64770Sstevel@tonic-gate 			bcnt -= n;
64780Sstevel@tonic-gate 			if (bcnt == 0)
64790Sstevel@tonic-gate 				break;
64800Sstevel@tonic-gate 		}
64810Sstevel@tonic-gate 		mctl->len = mctl->maxlen - bcnt;
64820Sstevel@tonic-gate 	} else
64830Sstevel@tonic-gate 		mctl->len = -1;
64840Sstevel@tonic-gate 
64850Sstevel@tonic-gate 	if (bp && bp->b_datap->db_type != M_DATA) {
64860Sstevel@tonic-gate 		/*
64870Sstevel@tonic-gate 		 * More PROTO blocks in msg.
64880Sstevel@tonic-gate 		 */
64890Sstevel@tonic-gate 		more |= MORECTL;
64900Sstevel@tonic-gate 		savemp = bp;
64910Sstevel@tonic-gate 		while (bp && bp->b_datap->db_type != M_DATA) {
64920Sstevel@tonic-gate 			savemptail = bp;
64930Sstevel@tonic-gate 			bp = bp->b_cont;
64940Sstevel@tonic-gate 		}
64950Sstevel@tonic-gate 		savemptail->b_cont = NULL;
64960Sstevel@tonic-gate 	}
64970Sstevel@tonic-gate 
64980Sstevel@tonic-gate 	/*
64990Sstevel@tonic-gate 	 * Now process DATA blocks, if any.
65000Sstevel@tonic-gate 	 */
65010Sstevel@tonic-gate 	if (mdata->maxlen >= 0 && bp) {
65020Sstevel@tonic-gate 		/*
65030Sstevel@tonic-gate 		 * struiocopyout will consume a potential zero-length
65040Sstevel@tonic-gate 		 * M_DATA even if uio_resid is zero.
65050Sstevel@tonic-gate 		 */
65060Sstevel@tonic-gate 		size_t oldresid = uiop->uio_resid;
65070Sstevel@tonic-gate 
65080Sstevel@tonic-gate 		bp = struiocopyout(bp, uiop, &error);
65090Sstevel@tonic-gate 		if (error != 0) {
65100Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
65110Sstevel@tonic-gate 			/*
65120Sstevel@tonic-gate 			 * clear stream head hi pri flag based on
65130Sstevel@tonic-gate 			 * first message
65140Sstevel@tonic-gate 			 */
65150Sstevel@tonic-gate 			if (type >= QPCTL) {
65160Sstevel@tonic-gate 				ASSERT(type == M_PCPROTO);
65170Sstevel@tonic-gate 				stp->sd_flag &= ~STRPRI;
65180Sstevel@tonic-gate 			}
65190Sstevel@tonic-gate 			more = 0;
65200Sstevel@tonic-gate 			freemsg(savemp);
65210Sstevel@tonic-gate 			goto getmout;
65220Sstevel@tonic-gate 		}
65230Sstevel@tonic-gate 		/*
65240Sstevel@tonic-gate 		 * (pr == 1) indicates a partial read.
65250Sstevel@tonic-gate 		 */
65260Sstevel@tonic-gate 		if (oldresid > uiop->uio_resid)
65270Sstevel@tonic-gate 			pr = 1;
65280Sstevel@tonic-gate 		mdata->len = mdata->maxlen - uiop->uio_resid;
65290Sstevel@tonic-gate 	} else
65300Sstevel@tonic-gate 		mdata->len = -1;
65310Sstevel@tonic-gate 
65320Sstevel@tonic-gate 	if (bp) {			/* more data blocks in msg */
65330Sstevel@tonic-gate 		more |= MOREDATA;
65340Sstevel@tonic-gate 		if (savemp)
65350Sstevel@tonic-gate 			savemptail->b_cont = bp;
65360Sstevel@tonic-gate 		else
65370Sstevel@tonic-gate 			savemp = bp;
65380Sstevel@tonic-gate 	}
65390Sstevel@tonic-gate 
65400Sstevel@tonic-gate 	mutex_enter(&stp->sd_lock);
65410Sstevel@tonic-gate 	if (savemp) {
65420Sstevel@tonic-gate 		if (pr && (savemp->b_datap->db_type == M_DATA) &&
65430Sstevel@tonic-gate 		    msgnodata(savemp)) {
65440Sstevel@tonic-gate 			/*
65450Sstevel@tonic-gate 			 * Avoid queuing a zero-length tail part of
65460Sstevel@tonic-gate 			 * a message. pr=1 indicates that we read some of
65470Sstevel@tonic-gate 			 * the message.
65480Sstevel@tonic-gate 			 */
65490Sstevel@tonic-gate 			freemsg(savemp);
65500Sstevel@tonic-gate 			more &= ~MOREDATA;
65510Sstevel@tonic-gate 			/*
65520Sstevel@tonic-gate 			 * clear stream head hi pri flag based on
65530Sstevel@tonic-gate 			 * first message
65540Sstevel@tonic-gate 			 */
65550Sstevel@tonic-gate 			if (type >= QPCTL) {
65560Sstevel@tonic-gate 				ASSERT(type == M_PCPROTO);
65570Sstevel@tonic-gate 				stp->sd_flag &= ~STRPRI;
65580Sstevel@tonic-gate 			}
65590Sstevel@tonic-gate 		} else {
65600Sstevel@tonic-gate 			savemp->b_band = pri;
65610Sstevel@tonic-gate 			/*
65620Sstevel@tonic-gate 			 * If the first message was HIPRI and the one we're
65630Sstevel@tonic-gate 			 * putting back isn't, then clear STRPRI, otherwise
65640Sstevel@tonic-gate 			 * set STRPRI again.  Note that we must set STRPRI
65650Sstevel@tonic-gate 			 * again since the flush logic in strrput_nondata()
65660Sstevel@tonic-gate 			 * may have cleared it while we had sd_lock dropped.
65670Sstevel@tonic-gate 			 */
65680Sstevel@tonic-gate 			if (type >= QPCTL) {
65690Sstevel@tonic-gate 				ASSERT(type == M_PCPROTO);
65700Sstevel@tonic-gate 				if (queclass(savemp) < QPCTL)
65710Sstevel@tonic-gate 					stp->sd_flag &= ~STRPRI;
65720Sstevel@tonic-gate 				else
65730Sstevel@tonic-gate 					stp->sd_flag |= STRPRI;
65740Sstevel@tonic-gate 			} else if (queclass(savemp) >= QPCTL) {
65750Sstevel@tonic-gate 				/*
65760Sstevel@tonic-gate 				 * The first message was not a HIPRI message,
65770Sstevel@tonic-gate 				 * but the one we are about to putback is.
65780Sstevel@tonic-gate 				 * For simplicitly, we do not allow for HIPRI
65790Sstevel@tonic-gate 				 * messages to be embedded in the message
65800Sstevel@tonic-gate 				 * body, so just force it to same type as
65810Sstevel@tonic-gate 				 * first message.
65820Sstevel@tonic-gate 				 */
65830Sstevel@tonic-gate 				ASSERT(type == M_DATA || type == M_PROTO);
65840Sstevel@tonic-gate 				ASSERT(savemp->b_datap->db_type == M_PCPROTO);
65850Sstevel@tonic-gate 				savemp->b_datap->db_type = type;
65860Sstevel@tonic-gate 			}
65870Sstevel@tonic-gate 			if (mark != 0) {
65880Sstevel@tonic-gate 				savemp->b_flag |= mark & ~_LASTMARK;
65890Sstevel@tonic-gate 				if ((mark & _LASTMARK) &&
65900Sstevel@tonic-gate 				    (stp->sd_mark == NULL)) {
65910Sstevel@tonic-gate 					/*
65920Sstevel@tonic-gate 					 * If another marked message arrived
65930Sstevel@tonic-gate 					 * while sd_lock was not held sd_mark
65940Sstevel@tonic-gate 					 * would be non-NULL.
65950Sstevel@tonic-gate 					 */
65960Sstevel@tonic-gate 					stp->sd_mark = savemp;
65970Sstevel@tonic-gate 				}
65980Sstevel@tonic-gate 			}
65990Sstevel@tonic-gate 			putback(stp, q, savemp, pri);
66000Sstevel@tonic-gate 		}
66010Sstevel@tonic-gate 	} else {
66020Sstevel@tonic-gate 		/*
66030Sstevel@tonic-gate 		 * The complete message was consumed.
66040Sstevel@tonic-gate 		 *
66050Sstevel@tonic-gate 		 * If another M_PCPROTO arrived while sd_lock was not held
66060Sstevel@tonic-gate 		 * it would have been discarded since STRPRI was still set.
66070Sstevel@tonic-gate 		 *
66080Sstevel@tonic-gate 		 * Move the MSG*MARKNEXT information
66090Sstevel@tonic-gate 		 * to the stream head just in case
66100Sstevel@tonic-gate 		 * the read queue becomes empty.
66110Sstevel@tonic-gate 		 * clear stream head hi pri flag based on
66120Sstevel@tonic-gate 		 * first message
66130Sstevel@tonic-gate 		 *
66140Sstevel@tonic-gate 		 * If the stream head was at the mark
66150Sstevel@tonic-gate 		 * (STRATMARK) before we dropped sd_lock above
66160Sstevel@tonic-gate 		 * and some data was consumed then we have
66170Sstevel@tonic-gate 		 * moved past the mark thus STRATMARK is
66180Sstevel@tonic-gate 		 * cleared. However, if a message arrived in
66190Sstevel@tonic-gate 		 * strrput during the copyout above causing
66200Sstevel@tonic-gate 		 * STRATMARK to be set we can not clear that
66210Sstevel@tonic-gate 		 * flag.
66220Sstevel@tonic-gate 		 */
66230Sstevel@tonic-gate 		if (type >= QPCTL) {
66240Sstevel@tonic-gate 			ASSERT(type == M_PCPROTO);
66250Sstevel@tonic-gate 			stp->sd_flag &= ~STRPRI;
66260Sstevel@tonic-gate 		}
66270Sstevel@tonic-gate 		if (mark & (MSGMARKNEXT|MSGNOTMARKNEXT|MSGMARK)) {
66280Sstevel@tonic-gate 			if (mark & MSGMARKNEXT) {
66290Sstevel@tonic-gate 				stp->sd_flag &= ~STRNOTATMARK;
66300Sstevel@tonic-gate 				stp->sd_flag |= STRATMARK;
66310Sstevel@tonic-gate 			} else if (mark & MSGNOTMARKNEXT) {
66320Sstevel@tonic-gate 				stp->sd_flag &= ~STRATMARK;
66330Sstevel@tonic-gate 				stp->sd_flag |= STRNOTATMARK;
66340Sstevel@tonic-gate 			} else {
66350Sstevel@tonic-gate 				stp->sd_flag &= ~(STRATMARK|STRNOTATMARK);
66360Sstevel@tonic-gate 			}
66370Sstevel@tonic-gate 		} else if (pr && (old_sd_flag & STRATMARK)) {
66380Sstevel@tonic-gate 			stp->sd_flag &= ~STRATMARK;
66390Sstevel@tonic-gate 		}
66400Sstevel@tonic-gate 	}
66410Sstevel@tonic-gate 
66420Sstevel@tonic-gate 	*flagsp = flg;
66430Sstevel@tonic-gate 	*prip = pri;
66440Sstevel@tonic-gate 
66450Sstevel@tonic-gate 	/*
66460Sstevel@tonic-gate 	 * Getmsg cleanup processing - if the state of the queue has changed
66470Sstevel@tonic-gate 	 * some signals may need to be sent and/or poll awakened.
66480Sstevel@tonic-gate 	 */
66490Sstevel@tonic-gate getmout:
66500Sstevel@tonic-gate 	qbackenable(q, pri);
66510Sstevel@tonic-gate 
66520Sstevel@tonic-gate 	/*
66530Sstevel@tonic-gate 	 * We dropped the stream head lock above. Send all M_SIG messages
66540Sstevel@tonic-gate 	 * before processing stream head for SIGPOLL messages.
66550Sstevel@tonic-gate 	 */
66560Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&stp->sd_lock));
66570Sstevel@tonic-gate 	while ((bp = q->q_first) != NULL &&
66580Sstevel@tonic-gate 	    (bp->b_datap->db_type == M_SIG)) {
66590Sstevel@tonic-gate 		/*
66600Sstevel@tonic-gate 		 * sd_lock is held so the content of the read queue can not
66610Sstevel@tonic-gate 		 * change.
66620Sstevel@tonic-gate 		 */
66630Sstevel@tonic-gate 		bp = getq(q);
66640Sstevel@tonic-gate 		ASSERT(bp != NULL && bp->b_datap->db_type == M_SIG);
66650Sstevel@tonic-gate 
66660Sstevel@tonic-gate 		strsignal_nolock(stp, *bp->b_rptr, (int32_t)bp->b_band);
66670Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
66680Sstevel@tonic-gate 		freemsg(bp);
66690Sstevel@tonic-gate 		if (STREAM_NEEDSERVICE(stp))
66700Sstevel@tonic-gate 			stream_runservice(stp);
66710Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
66720Sstevel@tonic-gate 	}
66730Sstevel@tonic-gate 
66740Sstevel@tonic-gate 	/*
66750Sstevel@tonic-gate 	 * stream head cannot change while we make the determination
66760Sstevel@tonic-gate 	 * whether or not to send a signal. Drop the flag to allow strrput
66770Sstevel@tonic-gate 	 * to send firstmsgsigs again.
66780Sstevel@tonic-gate 	 */
66790Sstevel@tonic-gate 	stp->sd_flag &= ~STRGETINPROG;
66800Sstevel@tonic-gate 
66810Sstevel@tonic-gate 	/*
66820Sstevel@tonic-gate 	 * If the type of message at the front of the queue changed
66830Sstevel@tonic-gate 	 * due to the receive the appropriate signals and pollwakeup events
66840Sstevel@tonic-gate 	 * are generated. The type of changes are:
66850Sstevel@tonic-gate 	 *	Processed a hipri message, q_first is not hipri.
66860Sstevel@tonic-gate 	 *	Processed a band X message, and q_first is band Y.
66870Sstevel@tonic-gate 	 * The generated signals and pollwakeups are identical to what
66880Sstevel@tonic-gate 	 * strrput() generates should the message that is now on q_first
66890Sstevel@tonic-gate 	 * arrive to an empty read queue.
66900Sstevel@tonic-gate 	 *
66910Sstevel@tonic-gate 	 * Note: only strrput will send a signal for a hipri message.
66920Sstevel@tonic-gate 	 */
66930Sstevel@tonic-gate 	if ((bp = q->q_first) != NULL && !(stp->sd_flag & STRPRI)) {
66940Sstevel@tonic-gate 		strsigset_t signals = 0;
66950Sstevel@tonic-gate 		strpollset_t pollwakeups = 0;
66960Sstevel@tonic-gate 
66970Sstevel@tonic-gate 		if (flg & MSG_HIPRI) {
66980Sstevel@tonic-gate 			/*
66990Sstevel@tonic-gate 			 * Removed a hipri message. Regular data at
67000Sstevel@tonic-gate 			 * the front of  the queue.
67010Sstevel@tonic-gate 			 */
67020Sstevel@tonic-gate 			if (bp->b_band == 0) {
67030Sstevel@tonic-gate 				signals = S_INPUT | S_RDNORM;
67040Sstevel@tonic-gate 				pollwakeups = POLLIN | POLLRDNORM;
67050Sstevel@tonic-gate 			} else {
67060Sstevel@tonic-gate 				signals = S_INPUT | S_RDBAND;
67070Sstevel@tonic-gate 				pollwakeups = POLLIN | POLLRDBAND;
67080Sstevel@tonic-gate 			}
67090Sstevel@tonic-gate 		} else if (pri != bp->b_band) {
67100Sstevel@tonic-gate 			/*
67110Sstevel@tonic-gate 			 * The band is different for the new q_first.
67120Sstevel@tonic-gate 			 */
67130Sstevel@tonic-gate 			if (bp->b_band == 0) {
67140Sstevel@tonic-gate 				signals = S_RDNORM;
67150Sstevel@tonic-gate 				pollwakeups = POLLIN | POLLRDNORM;
67160Sstevel@tonic-gate 			} else {
67170Sstevel@tonic-gate 				signals = S_RDBAND;
67180Sstevel@tonic-gate 				pollwakeups = POLLIN | POLLRDBAND;
67190Sstevel@tonic-gate 			}
67200Sstevel@tonic-gate 		}
67210Sstevel@tonic-gate 
67220Sstevel@tonic-gate 		if (pollwakeups != 0) {
67230Sstevel@tonic-gate 			if (pollwakeups == (POLLIN | POLLRDNORM)) {
67240Sstevel@tonic-gate 				if (!(stp->sd_rput_opt & SR_POLLIN))
67250Sstevel@tonic-gate 					goto no_pollwake;
67260Sstevel@tonic-gate 				stp->sd_rput_opt &= ~SR_POLLIN;
67270Sstevel@tonic-gate 			}
67280Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
67290Sstevel@tonic-gate 			pollwakeup(&stp->sd_pollist, pollwakeups);
67300Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
67310Sstevel@tonic-gate 		}
67320Sstevel@tonic-gate no_pollwake:
67330Sstevel@tonic-gate 
67340Sstevel@tonic-gate 		if (stp->sd_sigflags & signals)
67350Sstevel@tonic-gate 			strsendsig(stp->sd_siglist, signals, bp->b_band, 0);
67360Sstevel@tonic-gate 	}
67370Sstevel@tonic-gate 	mutex_exit(&stp->sd_lock);
67380Sstevel@tonic-gate 
67390Sstevel@tonic-gate 	rvp->r_val1 = more;
67400Sstevel@tonic-gate 	return (error);
67410Sstevel@tonic-gate #undef	_LASTMARK
67420Sstevel@tonic-gate }
67430Sstevel@tonic-gate 
67440Sstevel@tonic-gate /*
67450Sstevel@tonic-gate  * Get the next message from the read queue.  If the message is
67460Sstevel@tonic-gate  * priority, STRPRI will have been set by strrput().  This flag
67470Sstevel@tonic-gate  * should be reset only when the entire message at the front of the
67480Sstevel@tonic-gate  * queue as been consumed.
67490Sstevel@tonic-gate  *
67500Sstevel@tonic-gate  * If uiop is NULL all data is returned in mctlp.
67510Sstevel@tonic-gate  * Note that a NULL uiop implies that FNDELAY and FNONBLOCK are assumed
67520Sstevel@tonic-gate  * not enabled.
67530Sstevel@tonic-gate  * The timeout parameter is in milliseconds; -1 for infinity.
67540Sstevel@tonic-gate  * This routine handles the consolidation private flags:
67550Sstevel@tonic-gate  *	MSG_IGNERROR	Ignore any stream head error except STPLEX.
67560Sstevel@tonic-gate  *	MSG_DELAYERROR	Defer the error check until the queue is empty.
67570Sstevel@tonic-gate  *	MSG_HOLDSIG	Hold signals while waiting for data.
67580Sstevel@tonic-gate  *	MSG_IPEEK	Only peek at messages.
67590Sstevel@tonic-gate  *	MSG_DISCARDTAIL	Discard the tail M_DATA part of the message
67600Sstevel@tonic-gate  *			that doesn't fit.
67610Sstevel@tonic-gate  *	MSG_NOMARK	If the message is marked leave it on the queue.
67620Sstevel@tonic-gate  *
67630Sstevel@tonic-gate  * NOTE: strgetmsg and kstrgetmsg have much of the logic in common.
67640Sstevel@tonic-gate  */
67650Sstevel@tonic-gate int
67660Sstevel@tonic-gate kstrgetmsg(
67670Sstevel@tonic-gate 	struct vnode *vp,
67680Sstevel@tonic-gate 	mblk_t **mctlp,
67690Sstevel@tonic-gate 	struct uio *uiop,
67700Sstevel@tonic-gate 	unsigned char *prip,
67710Sstevel@tonic-gate 	int *flagsp,
67720Sstevel@tonic-gate 	clock_t timout,
67730Sstevel@tonic-gate 	rval_t *rvp)
67740Sstevel@tonic-gate {
67750Sstevel@tonic-gate 	struct stdata *stp;
67760Sstevel@tonic-gate 	mblk_t *bp, *nbp;
67770Sstevel@tonic-gate 	mblk_t *savemp = NULL;
67780Sstevel@tonic-gate 	mblk_t *savemptail = NULL;
67790Sstevel@tonic-gate 	int flags;
67800Sstevel@tonic-gate 	uint_t old_sd_flag;
67810Sstevel@tonic-gate 	int flg;
67820Sstevel@tonic-gate 	int more = 0;
67830Sstevel@tonic-gate 	int error = 0;
67840Sstevel@tonic-gate 	char first = 1;
67850Sstevel@tonic-gate 	uint_t mark;		/* Contains MSG*MARK and _LASTMARK */
67860Sstevel@tonic-gate #define	_LASTMARK	0x8000	/* Distinct from MSG*MARK */
67870Sstevel@tonic-gate 	unsigned char pri = 0;
67880Sstevel@tonic-gate 	queue_t *q;
67890Sstevel@tonic-gate 	int	pr = 0;			/* Partial read successful */
67900Sstevel@tonic-gate 	unsigned char type;
67910Sstevel@tonic-gate 
67920Sstevel@tonic-gate 	TRACE_1(TR_FAC_STREAMS_FR, TR_KSTRGETMSG_ENTER,
67930Sstevel@tonic-gate 		"kstrgetmsg:%p", vp);
67940Sstevel@tonic-gate 
67950Sstevel@tonic-gate 	ASSERT(vp->v_stream);
67960Sstevel@tonic-gate 	stp = vp->v_stream;
67970Sstevel@tonic-gate 	rvp->r_val1 = 0;
67980Sstevel@tonic-gate 
67990Sstevel@tonic-gate 	if (stp->sd_sidp != NULL && stp->sd_vnode->v_type != VFIFO)
68000Sstevel@tonic-gate 		if (error = straccess(stp, JCREAD))
68010Sstevel@tonic-gate 			return (error);
68020Sstevel@tonic-gate 
68030Sstevel@tonic-gate 	flags = *flagsp;
68040Sstevel@tonic-gate 	/* Fast check of flags before acquiring the lock */
68050Sstevel@tonic-gate 	if (stp->sd_flag & (STRDERR|STPLEX)) {
68060Sstevel@tonic-gate 		if ((stp->sd_flag & STPLEX) ||
68070Sstevel@tonic-gate 		    (flags & (MSG_IGNERROR|MSG_DELAYERROR)) == 0) {
68080Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
68090Sstevel@tonic-gate 			error = strgeterr(stp, STRDERR|STPLEX,
68100Sstevel@tonic-gate 					(flags & MSG_IPEEK));
68110Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
68120Sstevel@tonic-gate 			if (error != 0)
68130Sstevel@tonic-gate 				return (error);
68140Sstevel@tonic-gate 		}
68150Sstevel@tonic-gate 	}
68160Sstevel@tonic-gate 
68170Sstevel@tonic-gate 	switch (flags & (MSG_HIPRI|MSG_ANY|MSG_BAND)) {
68180Sstevel@tonic-gate 	case MSG_HIPRI:
68190Sstevel@tonic-gate 		if (*prip != 0)
68200Sstevel@tonic-gate 			return (EINVAL);
68210Sstevel@tonic-gate 		break;
68220Sstevel@tonic-gate 
68230Sstevel@tonic-gate 	case MSG_ANY:
68240Sstevel@tonic-gate 	case MSG_BAND:
68250Sstevel@tonic-gate 		break;
68260Sstevel@tonic-gate 
68270Sstevel@tonic-gate 	default:
68280Sstevel@tonic-gate 		return (EINVAL);
68290Sstevel@tonic-gate 	}
68300Sstevel@tonic-gate 
68310Sstevel@tonic-gate retry:
68320Sstevel@tonic-gate 	q = _RD(stp->sd_wrq);
68330Sstevel@tonic-gate 	mutex_enter(&stp->sd_lock);
68340Sstevel@tonic-gate 	old_sd_flag = stp->sd_flag;
68350Sstevel@tonic-gate 	mark = 0;
68360Sstevel@tonic-gate 	for (;;) {
68370Sstevel@tonic-gate 		int done = 0;
68380Sstevel@tonic-gate 		int waitflag;
68390Sstevel@tonic-gate 		int fmode;
68400Sstevel@tonic-gate 		mblk_t *q_first = q->q_first;
68410Sstevel@tonic-gate 
68420Sstevel@tonic-gate 		/*
68430Sstevel@tonic-gate 		 * This section of the code operates just like the code
68440Sstevel@tonic-gate 		 * in strgetmsg().  There is a comment there about what
68450Sstevel@tonic-gate 		 * is going on here.
68460Sstevel@tonic-gate 		 */
68470Sstevel@tonic-gate 		if (!(flags & (MSG_HIPRI|MSG_BAND))) {
68480Sstevel@tonic-gate 			/* Asking for normal, band0 data */
68490Sstevel@tonic-gate 			bp = strget(stp, q, uiop, first, &error);
68500Sstevel@tonic-gate 			ASSERT(MUTEX_HELD(&stp->sd_lock));
68510Sstevel@tonic-gate 			if (bp != NULL) {
68520Sstevel@tonic-gate 				if (bp->b_datap->db_type == M_SIG) {
68530Sstevel@tonic-gate 					strsignal_nolock(stp, *bp->b_rptr,
68540Sstevel@tonic-gate 					    (int32_t)bp->b_band);
68550Sstevel@tonic-gate 					continue;
68560Sstevel@tonic-gate 				} else {
68570Sstevel@tonic-gate 					break;
68580Sstevel@tonic-gate 				}
68590Sstevel@tonic-gate 			}
68600Sstevel@tonic-gate 			if (error != 0) {
68610Sstevel@tonic-gate 				goto getmout;
68620Sstevel@tonic-gate 			}
68630Sstevel@tonic-gate 		/*
68640Sstevel@tonic-gate 		 * We can't depend on the value of STRPRI here because
68650Sstevel@tonic-gate 		 * the stream head may be in transit. Therefore, we
68660Sstevel@tonic-gate 		 * must look at the type of the first message to
68670Sstevel@tonic-gate 		 * determine if a high priority messages is waiting
68680Sstevel@tonic-gate 		 */
68690Sstevel@tonic-gate 		} else if ((flags & MSG_HIPRI) && q_first != NULL &&
68700Sstevel@tonic-gate 			    q_first->b_datap->db_type >= QPCTL &&
68710Sstevel@tonic-gate 			    (bp = getq_noenab(q)) != NULL) {
68720Sstevel@tonic-gate 			ASSERT(bp->b_datap->db_type >= QPCTL);
68730Sstevel@tonic-gate 			break;
68740Sstevel@tonic-gate 		} else if ((flags & MSG_BAND) && q_first != NULL &&
68750Sstevel@tonic-gate 			    ((q_first->b_band >= *prip) ||
68760Sstevel@tonic-gate 			    q_first->b_datap->db_type >= QPCTL) &&
68770Sstevel@tonic-gate 			    (bp = getq_noenab(q)) != NULL) {
68780Sstevel@tonic-gate 			/*
68790Sstevel@tonic-gate 			 * Asked for at least band "prip" and got either at
68800Sstevel@tonic-gate 			 * least that band or a hipri message.
68810Sstevel@tonic-gate 			 */
68820Sstevel@tonic-gate 			ASSERT(bp->b_band >= *prip ||
68830Sstevel@tonic-gate 				bp->b_datap->db_type >= QPCTL);
68840Sstevel@tonic-gate 			if (bp->b_datap->db_type == M_SIG) {
68850Sstevel@tonic-gate 				strsignal_nolock(stp, *bp->b_rptr,
68860Sstevel@tonic-gate 				    (int32_t)bp->b_band);
68870Sstevel@tonic-gate 				continue;
68880Sstevel@tonic-gate 			} else {
68890Sstevel@tonic-gate 				break;
68900Sstevel@tonic-gate 			}
68910Sstevel@tonic-gate 		}
68920Sstevel@tonic-gate 
68930Sstevel@tonic-gate 		/* No data. Time to sleep? */
68940Sstevel@tonic-gate 		qbackenable(q, 0);
68950Sstevel@tonic-gate 
68960Sstevel@tonic-gate 		/*
68970Sstevel@tonic-gate 		 * Delayed error notification?
68980Sstevel@tonic-gate 		 */
68990Sstevel@tonic-gate 		if ((stp->sd_flag & (STRDERR|STPLEX)) &&
69000Sstevel@tonic-gate 		    (flags & (MSG_IGNERROR|MSG_DELAYERROR)) == MSG_DELAYERROR) {
69010Sstevel@tonic-gate 			error = strgeterr(stp, STRDERR|STPLEX,
69020Sstevel@tonic-gate 					(flags & MSG_IPEEK));
69030Sstevel@tonic-gate 			if (error != 0) {
69040Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
69050Sstevel@tonic-gate 				return (error);
69060Sstevel@tonic-gate 			}
69070Sstevel@tonic-gate 		}
69080Sstevel@tonic-gate 
69090Sstevel@tonic-gate 		/*
69100Sstevel@tonic-gate 		 * If STRHUP or STREOF, return 0 length control and data.
69110Sstevel@tonic-gate 		 * If a read(fd,buf,0) has been done, do not sleep, just
69120Sstevel@tonic-gate 		 * return.
69130Sstevel@tonic-gate 		 *
69140Sstevel@tonic-gate 		 * If mctlp == NULL and uiop == NULL, then the code will
69150Sstevel@tonic-gate 		 * do the strwaitq. This is an understood way of saying
69160Sstevel@tonic-gate 		 * sleep "polling" until a message is received.
69170Sstevel@tonic-gate 		 */
69180Sstevel@tonic-gate 		if ((stp->sd_flag & (STRHUP|STREOF)) ||
69190Sstevel@tonic-gate 		    (uiop != NULL && uiop->uio_resid == 0)) {
69200Sstevel@tonic-gate 			if (mctlp != NULL)
69210Sstevel@tonic-gate 				*mctlp = NULL;
69220Sstevel@tonic-gate 			*flagsp = 0;
69230Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
69240Sstevel@tonic-gate 			return (0);
69250Sstevel@tonic-gate 		}
69260Sstevel@tonic-gate 
69270Sstevel@tonic-gate 		waitflag = GETWAIT;
69280Sstevel@tonic-gate 		if (flags &
69290Sstevel@tonic-gate 		    (MSG_HOLDSIG|MSG_IGNERROR|MSG_IPEEK|MSG_DELAYERROR)) {
69300Sstevel@tonic-gate 			if (flags & MSG_HOLDSIG)
69310Sstevel@tonic-gate 				waitflag |= STR_NOSIG;
69320Sstevel@tonic-gate 			if (flags & MSG_IGNERROR)
69330Sstevel@tonic-gate 				waitflag |= STR_NOERROR;
69340Sstevel@tonic-gate 			if (flags & MSG_IPEEK)
69350Sstevel@tonic-gate 				waitflag |= STR_PEEK;
69360Sstevel@tonic-gate 			if (flags & MSG_DELAYERROR)
69370Sstevel@tonic-gate 				waitflag |= STR_DELAYERR;
69380Sstevel@tonic-gate 		}
69390Sstevel@tonic-gate 		if (uiop != NULL)
69400Sstevel@tonic-gate 			fmode = uiop->uio_fmode;
69410Sstevel@tonic-gate 		else
69420Sstevel@tonic-gate 			fmode = 0;
69430Sstevel@tonic-gate 
69440Sstevel@tonic-gate 		TRACE_2(TR_FAC_STREAMS_FR, TR_KSTRGETMSG_WAIT,
69450Sstevel@tonic-gate 			"kstrgetmsg calls strwaitq:%p, %p",
69460Sstevel@tonic-gate 			vp, uiop);
69470Sstevel@tonic-gate 		if (((error = strwaitq(stp, waitflag, (ssize_t)0,
69480Sstevel@tonic-gate 		    fmode, timout, &done)) != 0) || done) {
69490Sstevel@tonic-gate 			TRACE_2(TR_FAC_STREAMS_FR, TR_KSTRGETMSG_DONE,
69500Sstevel@tonic-gate 				"kstrgetmsg error or done:%p, %p",
69510Sstevel@tonic-gate 				vp, uiop);
69520Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
69530Sstevel@tonic-gate 			return (error);
69540Sstevel@tonic-gate 		}
69550Sstevel@tonic-gate 		TRACE_2(TR_FAC_STREAMS_FR, TR_KSTRGETMSG_AWAKE,
69560Sstevel@tonic-gate 			"kstrgetmsg awakes:%p, %p", vp, uiop);
69570Sstevel@tonic-gate 		if (stp->sd_sidp != NULL && stp->sd_vnode->v_type != VFIFO) {
69580Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
69590Sstevel@tonic-gate 			if (error = straccess(stp, JCREAD))
69600Sstevel@tonic-gate 				return (error);
69610Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
69620Sstevel@tonic-gate 		}
69630Sstevel@tonic-gate 		first = 0;
69640Sstevel@tonic-gate 	}
69650Sstevel@tonic-gate 	ASSERT(bp != NULL);
69660Sstevel@tonic-gate 	/*
69670Sstevel@tonic-gate 	 * Extract any mark information. If the message is not completely
69680Sstevel@tonic-gate 	 * consumed this information will be put in the mblk
69690Sstevel@tonic-gate 	 * that is putback.
69700Sstevel@tonic-gate 	 * If MSGMARKNEXT is set and the message is completely consumed
69710Sstevel@tonic-gate 	 * the STRATMARK flag will be set below. Likewise, if
69720Sstevel@tonic-gate 	 * MSGNOTMARKNEXT is set and the message is
69730Sstevel@tonic-gate 	 * completely consumed STRNOTATMARK will be set.
69740Sstevel@tonic-gate 	 */
69750Sstevel@tonic-gate 	mark = bp->b_flag & (MSGMARK | MSGMARKNEXT | MSGNOTMARKNEXT);
69760Sstevel@tonic-gate 	ASSERT((mark & (MSGMARKNEXT|MSGNOTMARKNEXT)) !=
69770Sstevel@tonic-gate 		(MSGMARKNEXT|MSGNOTMARKNEXT));
69780Sstevel@tonic-gate 	pri = bp->b_band;
69790Sstevel@tonic-gate 	if (mark != 0) {
69800Sstevel@tonic-gate 		/*
69810Sstevel@tonic-gate 		 * If the caller doesn't want the mark return.
69820Sstevel@tonic-gate 		 * Used to implement MSG_WAITALL in sockets.
69830Sstevel@tonic-gate 		 */
69840Sstevel@tonic-gate 		if (flags & MSG_NOMARK) {
69850Sstevel@tonic-gate 			putback(stp, q, bp, pri);
69860Sstevel@tonic-gate 			qbackenable(q, pri);
69870Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
69880Sstevel@tonic-gate 			return (EWOULDBLOCK);
69890Sstevel@tonic-gate 		}
69900Sstevel@tonic-gate 		if (bp == stp->sd_mark) {
69910Sstevel@tonic-gate 			mark |= _LASTMARK;
69920Sstevel@tonic-gate 			stp->sd_mark = NULL;
69930Sstevel@tonic-gate 		}
69940Sstevel@tonic-gate 	}
69950Sstevel@tonic-gate 
69960Sstevel@tonic-gate 	/*
69970Sstevel@tonic-gate 	 * keep track of the first message type
69980Sstevel@tonic-gate 	 */
69990Sstevel@tonic-gate 	type = bp->b_datap->db_type;
70000Sstevel@tonic-gate 
70010Sstevel@tonic-gate 	if (bp->b_datap->db_type == M_PASSFP) {
70020Sstevel@tonic-gate 		if ((mark & _LASTMARK) && (stp->sd_mark == NULL))
70030Sstevel@tonic-gate 			stp->sd_mark = bp;
70040Sstevel@tonic-gate 		bp->b_flag |= mark & ~_LASTMARK;
70050Sstevel@tonic-gate 		putback(stp, q, bp, pri);
70060Sstevel@tonic-gate 		qbackenable(q, pri);
70070Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
70080Sstevel@tonic-gate 		return (EBADMSG);
70090Sstevel@tonic-gate 	}
70100Sstevel@tonic-gate 	ASSERT(type != M_SIG);
70110Sstevel@tonic-gate 
70120Sstevel@tonic-gate 	if (flags & MSG_IPEEK) {
70130Sstevel@tonic-gate 		/*
70140Sstevel@tonic-gate 		 * Clear any struioflag - we do the uiomove over again
70150Sstevel@tonic-gate 		 * when peeking since it simplifies the code.
70160Sstevel@tonic-gate 		 *
70170Sstevel@tonic-gate 		 * Dup the message and put the original back on the queue.
70180Sstevel@tonic-gate 		 * If dupmsg() fails, try again with copymsg() to see if
70190Sstevel@tonic-gate 		 * there is indeed a shortage of memory.  dupmsg() may fail
70200Sstevel@tonic-gate 		 * if db_ref in any of the messages reaches its limit.
70210Sstevel@tonic-gate 		 */
70220Sstevel@tonic-gate 		if ((nbp = dupmsg(bp)) == NULL && (nbp = copymsg(bp)) == NULL) {
70230Sstevel@tonic-gate 			/*
70240Sstevel@tonic-gate 			 * Restore the state of the stream head since we
70250Sstevel@tonic-gate 			 * need to drop sd_lock (strwaitbuf is sleeping).
70260Sstevel@tonic-gate 			 */
70270Sstevel@tonic-gate 			size_t size = msgdsize(bp);
70280Sstevel@tonic-gate 
70290Sstevel@tonic-gate 			if ((mark & _LASTMARK) && (stp->sd_mark == NULL))
70300Sstevel@tonic-gate 				stp->sd_mark = bp;
70310Sstevel@tonic-gate 			bp->b_flag |= mark & ~_LASTMARK;
70320Sstevel@tonic-gate 			putback(stp, q, bp, pri);
70330Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
70340Sstevel@tonic-gate 			error = strwaitbuf(size, BPRI_HI);
70350Sstevel@tonic-gate 			if (error) {
70360Sstevel@tonic-gate 				/*
70370Sstevel@tonic-gate 				 * There is no net change to the queue thus
70380Sstevel@tonic-gate 				 * no need to qbackenable.
70390Sstevel@tonic-gate 				 */
70400Sstevel@tonic-gate 				return (error);
70410Sstevel@tonic-gate 			}
70420Sstevel@tonic-gate 			goto retry;
70430Sstevel@tonic-gate 		}
70440Sstevel@tonic-gate 
70450Sstevel@tonic-gate 		if ((mark & _LASTMARK) && (stp->sd_mark == NULL))
70460Sstevel@tonic-gate 			stp->sd_mark = bp;
70470Sstevel@tonic-gate 		bp->b_flag |= mark & ~_LASTMARK;
70480Sstevel@tonic-gate 		putback(stp, q, bp, pri);
70490Sstevel@tonic-gate 		bp = nbp;
70500Sstevel@tonic-gate 	}
70510Sstevel@tonic-gate 
70520Sstevel@tonic-gate 	/*
70530Sstevel@tonic-gate 	 * Set this flag so strrput will not generate signals. Need to
70540Sstevel@tonic-gate 	 * make sure this flag is cleared before leaving this routine
70550Sstevel@tonic-gate 	 * else signals will stop being sent.
70560Sstevel@tonic-gate 	 */
70570Sstevel@tonic-gate 	stp->sd_flag |= STRGETINPROG;
70580Sstevel@tonic-gate 	mutex_exit(&stp->sd_lock);
70590Sstevel@tonic-gate 
7060*898Skais 	if ((stp->sd_rputdatafunc != NULL) && (DB_TYPE(bp) == M_DATA) &&
7061*898Skais 	    (!(DB_FLAGS(bp) & DBLK_COOKED))) {
7062*898Skais 
7063*898Skais 		bp = (stp->sd_rputdatafunc)(
7064*898Skais 		    stp->sd_vnode, bp, NULL,
7065*898Skais 		    NULL, NULL, NULL);
7066*898Skais 
7067*898Skais 		if (bp == NULL)
7068*898Skais 			goto retry;
7069*898Skais 
7070*898Skais 		DB_FLAGS(bp) |= DBLK_COOKED;
7071*898Skais 	}
7072*898Skais 
70730Sstevel@tonic-gate 	if (STREAM_NEEDSERVICE(stp))
70740Sstevel@tonic-gate 		stream_runservice(stp);
70750Sstevel@tonic-gate 
70760Sstevel@tonic-gate 	/*
70770Sstevel@tonic-gate 	 * Set HIPRI flag if message is priority.
70780Sstevel@tonic-gate 	 */
70790Sstevel@tonic-gate 	if (type >= QPCTL)
70800Sstevel@tonic-gate 		flg = MSG_HIPRI;
70810Sstevel@tonic-gate 	else
70820Sstevel@tonic-gate 		flg = MSG_BAND;
70830Sstevel@tonic-gate 
70840Sstevel@tonic-gate 	/*
70850Sstevel@tonic-gate 	 * First process PROTO or PCPROTO blocks, if any.
70860Sstevel@tonic-gate 	 */
70870Sstevel@tonic-gate 	if (mctlp != NULL && type != M_DATA) {
70880Sstevel@tonic-gate 		mblk_t *nbp;
70890Sstevel@tonic-gate 
70900Sstevel@tonic-gate 		*mctlp = bp;
70910Sstevel@tonic-gate 		while (bp->b_cont && bp->b_cont->b_datap->db_type != M_DATA)
70920Sstevel@tonic-gate 			bp = bp->b_cont;
70930Sstevel@tonic-gate 		nbp = bp->b_cont;
70940Sstevel@tonic-gate 		bp->b_cont = NULL;
70950Sstevel@tonic-gate 		bp = nbp;
70960Sstevel@tonic-gate 	}
70970Sstevel@tonic-gate 
70980Sstevel@tonic-gate 	if (bp && bp->b_datap->db_type != M_DATA) {
70990Sstevel@tonic-gate 		/*
71000Sstevel@tonic-gate 		 * More PROTO blocks in msg. Will only happen if mctlp is NULL.
71010Sstevel@tonic-gate 		 */
71020Sstevel@tonic-gate 		more |= MORECTL;
71030Sstevel@tonic-gate 		savemp = bp;
71040Sstevel@tonic-gate 		while (bp && bp->b_datap->db_type != M_DATA) {
71050Sstevel@tonic-gate 			savemptail = bp;
71060Sstevel@tonic-gate 			bp = bp->b_cont;
71070Sstevel@tonic-gate 		}
71080Sstevel@tonic-gate 		savemptail->b_cont = NULL;
71090Sstevel@tonic-gate 	}
71100Sstevel@tonic-gate 
71110Sstevel@tonic-gate 	/*
71120Sstevel@tonic-gate 	 * Now process DATA blocks, if any.
71130Sstevel@tonic-gate 	 */
71140Sstevel@tonic-gate 	if (uiop == NULL) {
71150Sstevel@tonic-gate 		/* Append data to tail of mctlp */
71160Sstevel@tonic-gate 		if (mctlp != NULL) {
71170Sstevel@tonic-gate 			mblk_t **mpp = mctlp;
71180Sstevel@tonic-gate 
71190Sstevel@tonic-gate 			while (*mpp != NULL)
71200Sstevel@tonic-gate 				mpp = &((*mpp)->b_cont);
71210Sstevel@tonic-gate 			*mpp = bp;
71220Sstevel@tonic-gate 			bp = NULL;
71230Sstevel@tonic-gate 		}
71240Sstevel@tonic-gate 	} else if (uiop->uio_resid >= 0 && bp) {
71250Sstevel@tonic-gate 		size_t oldresid = uiop->uio_resid;
71260Sstevel@tonic-gate 
71270Sstevel@tonic-gate 		/*
71280Sstevel@tonic-gate 		 * If a streams message is likely to consist
71290Sstevel@tonic-gate 		 * of many small mblks, it is pulled up into
71300Sstevel@tonic-gate 		 * one continuous chunk of memory.
71310Sstevel@tonic-gate 		 * see longer comment at top of page
71320Sstevel@tonic-gate 		 * by mblk_pull_len declaration.
71330Sstevel@tonic-gate 		 */
71340Sstevel@tonic-gate 
71350Sstevel@tonic-gate 		if (MBLKL(bp) < mblk_pull_len) {
71360Sstevel@tonic-gate 			(void) pullupmsg(bp, -1);
71370Sstevel@tonic-gate 		}
71380Sstevel@tonic-gate 
71390Sstevel@tonic-gate 		bp = struiocopyout(bp, uiop, &error);
71400Sstevel@tonic-gate 		if (error != 0) {
71410Sstevel@tonic-gate 			if (mctlp != NULL) {
71420Sstevel@tonic-gate 				freemsg(*mctlp);
71430Sstevel@tonic-gate 				*mctlp = NULL;
71440Sstevel@tonic-gate 			} else
71450Sstevel@tonic-gate 				freemsg(savemp);
71460Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
71470Sstevel@tonic-gate 			/*
71480Sstevel@tonic-gate 			 * clear stream head hi pri flag based on
71490Sstevel@tonic-gate 			 * first message
71500Sstevel@tonic-gate 			 */
71510Sstevel@tonic-gate 			if (!(flags & MSG_IPEEK) && (type >= QPCTL)) {
71520Sstevel@tonic-gate 				ASSERT(type == M_PCPROTO);
71530Sstevel@tonic-gate 				stp->sd_flag &= ~STRPRI;
71540Sstevel@tonic-gate 			}
71550Sstevel@tonic-gate 			more = 0;
71560Sstevel@tonic-gate 			goto getmout;
71570Sstevel@tonic-gate 		}
71580Sstevel@tonic-gate 		/*
71590Sstevel@tonic-gate 		 * (pr == 1) indicates a partial read.
71600Sstevel@tonic-gate 		 */
71610Sstevel@tonic-gate 		if (oldresid > uiop->uio_resid)
71620Sstevel@tonic-gate 			pr = 1;
71630Sstevel@tonic-gate 	}
71640Sstevel@tonic-gate 
71650Sstevel@tonic-gate 	if (bp) {			/* more data blocks in msg */
71660Sstevel@tonic-gate 		more |= MOREDATA;
71670Sstevel@tonic-gate 		if (savemp)
71680Sstevel@tonic-gate 			savemptail->b_cont = bp;
71690Sstevel@tonic-gate 		else
71700Sstevel@tonic-gate 			savemp = bp;
71710Sstevel@tonic-gate 	}
71720Sstevel@tonic-gate 
71730Sstevel@tonic-gate 	mutex_enter(&stp->sd_lock);
71740Sstevel@tonic-gate 	if (savemp) {
71750Sstevel@tonic-gate 		if (flags & (MSG_IPEEK|MSG_DISCARDTAIL)) {
71760Sstevel@tonic-gate 			/*
71770Sstevel@tonic-gate 			 * When MSG_DISCARDTAIL is set or
71780Sstevel@tonic-gate 			 * when peeking discard any tail. When peeking this
71790Sstevel@tonic-gate 			 * is the tail of the dup that was copied out - the
71800Sstevel@tonic-gate 			 * message has already been putback on the queue.
71810Sstevel@tonic-gate 			 * Return MOREDATA to the caller even though the data
71820Sstevel@tonic-gate 			 * is discarded. This is used by sockets (to
71830Sstevel@tonic-gate 			 * set MSG_TRUNC).
71840Sstevel@tonic-gate 			 */
71850Sstevel@tonic-gate 			freemsg(savemp);
71860Sstevel@tonic-gate 			if (!(flags & MSG_IPEEK) && (type >= QPCTL)) {
71870Sstevel@tonic-gate 				ASSERT(type == M_PCPROTO);
71880Sstevel@tonic-gate 				stp->sd_flag &= ~STRPRI;
71890Sstevel@tonic-gate 			}
71900Sstevel@tonic-gate 		} else if (pr && (savemp->b_datap->db_type == M_DATA) &&
71910Sstevel@tonic-gate 			    msgnodata(savemp)) {
71920Sstevel@tonic-gate 			/*
71930Sstevel@tonic-gate 			 * Avoid queuing a zero-length tail part of
71940Sstevel@tonic-gate 			 * a message. pr=1 indicates that we read some of
71950Sstevel@tonic-gate 			 * the message.
71960Sstevel@tonic-gate 			 */
71970Sstevel@tonic-gate 			freemsg(savemp);
71980Sstevel@tonic-gate 			more &= ~MOREDATA;
71990Sstevel@tonic-gate 			if (type >= QPCTL) {
72000Sstevel@tonic-gate 				ASSERT(type == M_PCPROTO);
72010Sstevel@tonic-gate 				stp->sd_flag &= ~STRPRI;
72020Sstevel@tonic-gate 			}
72030Sstevel@tonic-gate 		} else {
72040Sstevel@tonic-gate 			savemp->b_band = pri;
72050Sstevel@tonic-gate 			/*
72060Sstevel@tonic-gate 			 * If the first message was HIPRI and the one we're
72070Sstevel@tonic-gate 			 * putting back isn't, then clear STRPRI, otherwise
72080Sstevel@tonic-gate 			 * set STRPRI again.  Note that we must set STRPRI
72090Sstevel@tonic-gate 			 * again since the flush logic in strrput_nondata()
72100Sstevel@tonic-gate 			 * may have cleared it while we had sd_lock dropped.
72110Sstevel@tonic-gate 			 */
72120Sstevel@tonic-gate 			if (type >= QPCTL) {
72130Sstevel@tonic-gate 				ASSERT(type == M_PCPROTO);
72140Sstevel@tonic-gate 				if (queclass(savemp) < QPCTL)
72150Sstevel@tonic-gate 					stp->sd_flag &= ~STRPRI;
72160Sstevel@tonic-gate 				else
72170Sstevel@tonic-gate 					stp->sd_flag |= STRPRI;
72180Sstevel@tonic-gate 			} else if (queclass(savemp) >= QPCTL) {
72190Sstevel@tonic-gate 				/*
72200Sstevel@tonic-gate 				 * The first message was not a HIPRI message,
72210Sstevel@tonic-gate 				 * but the one we are about to putback is.
72220Sstevel@tonic-gate 				 * For simplicitly, we do not allow for HIPRI
72230Sstevel@tonic-gate 				 * messages to be embedded in the message
72240Sstevel@tonic-gate 				 * body, so just force it to same type as
72250Sstevel@tonic-gate 				 * first message.
72260Sstevel@tonic-gate 				 */
72270Sstevel@tonic-gate 				ASSERT(type == M_DATA || type == M_PROTO);
72280Sstevel@tonic-gate 				ASSERT(savemp->b_datap->db_type == M_PCPROTO);
72290Sstevel@tonic-gate 				savemp->b_datap->db_type = type;
72300Sstevel@tonic-gate 			}
72310Sstevel@tonic-gate 			if (mark != 0) {
72320Sstevel@tonic-gate 				if ((mark & _LASTMARK) &&
72330Sstevel@tonic-gate 				    (stp->sd_mark == NULL)) {
72340Sstevel@tonic-gate 					/*
72350Sstevel@tonic-gate 					 * If another marked message arrived
72360Sstevel@tonic-gate 					 * while sd_lock was not held sd_mark
72370Sstevel@tonic-gate 					 * would be non-NULL.
72380Sstevel@tonic-gate 					 */
72390Sstevel@tonic-gate 					stp->sd_mark = savemp;
72400Sstevel@tonic-gate 				}
72410Sstevel@tonic-gate 				savemp->b_flag |= mark & ~_LASTMARK;
72420Sstevel@tonic-gate 			}
72430Sstevel@tonic-gate 			putback(stp, q, savemp, pri);
72440Sstevel@tonic-gate 		}
72450Sstevel@tonic-gate 	} else if (!(flags & MSG_IPEEK)) {
72460Sstevel@tonic-gate 		/*
72470Sstevel@tonic-gate 		 * The complete message was consumed.
72480Sstevel@tonic-gate 		 *
72490Sstevel@tonic-gate 		 * If another M_PCPROTO arrived while sd_lock was not held
72500Sstevel@tonic-gate 		 * it would have been discarded since STRPRI was still set.
72510Sstevel@tonic-gate 		 *
72520Sstevel@tonic-gate 		 * Move the MSG*MARKNEXT information
72530Sstevel@tonic-gate 		 * to the stream head just in case
72540Sstevel@tonic-gate 		 * the read queue becomes empty.
72550Sstevel@tonic-gate 		 * clear stream head hi pri flag based on
72560Sstevel@tonic-gate 		 * first message
72570Sstevel@tonic-gate 		 *
72580Sstevel@tonic-gate 		 * If the stream head was at the mark
72590Sstevel@tonic-gate 		 * (STRATMARK) before we dropped sd_lock above
72600Sstevel@tonic-gate 		 * and some data was consumed then we have
72610Sstevel@tonic-gate 		 * moved past the mark thus STRATMARK is
72620Sstevel@tonic-gate 		 * cleared. However, if a message arrived in
72630Sstevel@tonic-gate 		 * strrput during the copyout above causing
72640Sstevel@tonic-gate 		 * STRATMARK to be set we can not clear that
72650Sstevel@tonic-gate 		 * flag.
72660Sstevel@tonic-gate 		 * XXX A "perimeter" would help by single-threading strrput,
72670Sstevel@tonic-gate 		 * strread, strgetmsg and kstrgetmsg.
72680Sstevel@tonic-gate 		 */
72690Sstevel@tonic-gate 		if (type >= QPCTL) {
72700Sstevel@tonic-gate 			ASSERT(type == M_PCPROTO);
72710Sstevel@tonic-gate 			stp->sd_flag &= ~STRPRI;
72720Sstevel@tonic-gate 		}
72730Sstevel@tonic-gate 		if (mark & (MSGMARKNEXT|MSGNOTMARKNEXT|MSGMARK)) {
72740Sstevel@tonic-gate 			if (mark & MSGMARKNEXT) {
72750Sstevel@tonic-gate 				stp->sd_flag &= ~STRNOTATMARK;
72760Sstevel@tonic-gate 				stp->sd_flag |= STRATMARK;
72770Sstevel@tonic-gate 			} else if (mark & MSGNOTMARKNEXT) {
72780Sstevel@tonic-gate 				stp->sd_flag &= ~STRATMARK;
72790Sstevel@tonic-gate 				stp->sd_flag |= STRNOTATMARK;
72800Sstevel@tonic-gate 			} else {
72810Sstevel@tonic-gate 				stp->sd_flag &= ~(STRATMARK|STRNOTATMARK);
72820Sstevel@tonic-gate 			}
72830Sstevel@tonic-gate 		} else if (pr && (old_sd_flag & STRATMARK)) {
72840Sstevel@tonic-gate 			stp->sd_flag &= ~STRATMARK;
72850Sstevel@tonic-gate 		}
72860Sstevel@tonic-gate 	}
72870Sstevel@tonic-gate 
72880Sstevel@tonic-gate 	*flagsp = flg;
72890Sstevel@tonic-gate 	*prip = pri;
72900Sstevel@tonic-gate 
72910Sstevel@tonic-gate 	/*
72920Sstevel@tonic-gate 	 * Getmsg cleanup processing - if the state of the queue has changed
72930Sstevel@tonic-gate 	 * some signals may need to be sent and/or poll awakened.
72940Sstevel@tonic-gate 	 */
72950Sstevel@tonic-gate getmout:
72960Sstevel@tonic-gate 	qbackenable(q, pri);
72970Sstevel@tonic-gate 
72980Sstevel@tonic-gate 	/*
72990Sstevel@tonic-gate 	 * We dropped the stream head lock above. Send all M_SIG messages
73000Sstevel@tonic-gate 	 * before processing stream head for SIGPOLL messages.
73010Sstevel@tonic-gate 	 */
73020Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&stp->sd_lock));
73030Sstevel@tonic-gate 	while ((bp = q->q_first) != NULL &&
73040Sstevel@tonic-gate 	    (bp->b_datap->db_type == M_SIG)) {
73050Sstevel@tonic-gate 		/*
73060Sstevel@tonic-gate 		 * sd_lock is held so the content of the read queue can not
73070Sstevel@tonic-gate 		 * change.
73080Sstevel@tonic-gate 		 */
73090Sstevel@tonic-gate 		bp = getq(q);
73100Sstevel@tonic-gate 		ASSERT(bp != NULL && bp->b_datap->db_type == M_SIG);
73110Sstevel@tonic-gate 
73120Sstevel@tonic-gate 		strsignal_nolock(stp, *bp->b_rptr, (int32_t)bp->b_band);
73130Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
73140Sstevel@tonic-gate 		freemsg(bp);
73150Sstevel@tonic-gate 		if (STREAM_NEEDSERVICE(stp))
73160Sstevel@tonic-gate 			stream_runservice(stp);
73170Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
73180Sstevel@tonic-gate 	}
73190Sstevel@tonic-gate 
73200Sstevel@tonic-gate 	/*
73210Sstevel@tonic-gate 	 * stream head cannot change while we make the determination
73220Sstevel@tonic-gate 	 * whether or not to send a signal. Drop the flag to allow strrput
73230Sstevel@tonic-gate 	 * to send firstmsgsigs again.
73240Sstevel@tonic-gate 	 */
73250Sstevel@tonic-gate 	stp->sd_flag &= ~STRGETINPROG;
73260Sstevel@tonic-gate 
73270Sstevel@tonic-gate 	/*
73280Sstevel@tonic-gate 	 * If the type of message at the front of the queue changed
73290Sstevel@tonic-gate 	 * due to the receive the appropriate signals and pollwakeup events
73300Sstevel@tonic-gate 	 * are generated. The type of changes are:
73310Sstevel@tonic-gate 	 *	Processed a hipri message, q_first is not hipri.
73320Sstevel@tonic-gate 	 *	Processed a band X message, and q_first is band Y.
73330Sstevel@tonic-gate 	 * The generated signals and pollwakeups are identical to what
73340Sstevel@tonic-gate 	 * strrput() generates should the message that is now on q_first
73350Sstevel@tonic-gate 	 * arrive to an empty read queue.
73360Sstevel@tonic-gate 	 *
73370Sstevel@tonic-gate 	 * Note: only strrput will send a signal for a hipri message.
73380Sstevel@tonic-gate 	 */
73390Sstevel@tonic-gate 	if ((bp = q->q_first) != NULL && !(stp->sd_flag & STRPRI)) {
73400Sstevel@tonic-gate 		strsigset_t signals = 0;
73410Sstevel@tonic-gate 		strpollset_t pollwakeups = 0;
73420Sstevel@tonic-gate 
73430Sstevel@tonic-gate 		if (flg & MSG_HIPRI) {
73440Sstevel@tonic-gate 			/*
73450Sstevel@tonic-gate 			 * Removed a hipri message. Regular data at
73460Sstevel@tonic-gate 			 * the front of  the queue.
73470Sstevel@tonic-gate 			 */
73480Sstevel@tonic-gate 			if (bp->b_band == 0) {
73490Sstevel@tonic-gate 				signals = S_INPUT | S_RDNORM;
73500Sstevel@tonic-gate 				pollwakeups = POLLIN | POLLRDNORM;
73510Sstevel@tonic-gate 			} else {
73520Sstevel@tonic-gate 				signals = S_INPUT | S_RDBAND;
73530Sstevel@tonic-gate 				pollwakeups = POLLIN | POLLRDBAND;
73540Sstevel@tonic-gate 			}
73550Sstevel@tonic-gate 		} else if (pri != bp->b_band) {
73560Sstevel@tonic-gate 			/*
73570Sstevel@tonic-gate 			 * The band is different for the new q_first.
73580Sstevel@tonic-gate 			 */
73590Sstevel@tonic-gate 			if (bp->b_band == 0) {
73600Sstevel@tonic-gate 				signals = S_RDNORM;
73610Sstevel@tonic-gate 				pollwakeups = POLLIN | POLLRDNORM;
73620Sstevel@tonic-gate 			} else {
73630Sstevel@tonic-gate 				signals = S_RDBAND;
73640Sstevel@tonic-gate 				pollwakeups = POLLIN | POLLRDBAND;
73650Sstevel@tonic-gate 			}
73660Sstevel@tonic-gate 		}
73670Sstevel@tonic-gate 
73680Sstevel@tonic-gate 		if (pollwakeups != 0) {
73690Sstevel@tonic-gate 			if (pollwakeups == (POLLIN | POLLRDNORM)) {
73700Sstevel@tonic-gate 				if (!(stp->sd_rput_opt & SR_POLLIN))
73710Sstevel@tonic-gate 					goto no_pollwake;
73720Sstevel@tonic-gate 				stp->sd_rput_opt &= ~SR_POLLIN;
73730Sstevel@tonic-gate 			}
73740Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
73750Sstevel@tonic-gate 			pollwakeup(&stp->sd_pollist, pollwakeups);
73760Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
73770Sstevel@tonic-gate 		}
73780Sstevel@tonic-gate no_pollwake:
73790Sstevel@tonic-gate 
73800Sstevel@tonic-gate 		if (stp->sd_sigflags & signals)
73810Sstevel@tonic-gate 			strsendsig(stp->sd_siglist, signals, bp->b_band, 0);
73820Sstevel@tonic-gate 	}
73830Sstevel@tonic-gate 	mutex_exit(&stp->sd_lock);
73840Sstevel@tonic-gate 
73850Sstevel@tonic-gate 	rvp->r_val1 = more;
73860Sstevel@tonic-gate 	return (error);
73870Sstevel@tonic-gate #undef	_LASTMARK
73880Sstevel@tonic-gate }
73890Sstevel@tonic-gate 
73900Sstevel@tonic-gate /*
73910Sstevel@tonic-gate  * Put a message downstream.
73920Sstevel@tonic-gate  *
73930Sstevel@tonic-gate  * NOTE: strputmsg and kstrputmsg have much of the logic in common.
73940Sstevel@tonic-gate  */
73950Sstevel@tonic-gate int
73960Sstevel@tonic-gate strputmsg(
73970Sstevel@tonic-gate 	struct vnode *vp,
73980Sstevel@tonic-gate 	struct strbuf *mctl,
73990Sstevel@tonic-gate 	struct strbuf *mdata,
74000Sstevel@tonic-gate 	unsigned char pri,
74010Sstevel@tonic-gate 	int flag,
74020Sstevel@tonic-gate 	int fmode)
74030Sstevel@tonic-gate {
74040Sstevel@tonic-gate 	struct stdata *stp;
74050Sstevel@tonic-gate 	queue_t *wqp;
74060Sstevel@tonic-gate 	mblk_t *mp;
74070Sstevel@tonic-gate 	ssize_t msgsize;
74080Sstevel@tonic-gate 	ssize_t rmin, rmax;
74090Sstevel@tonic-gate 	int error;
74100Sstevel@tonic-gate 	struct uio uios;
74110Sstevel@tonic-gate 	struct uio *uiop = &uios;
74120Sstevel@tonic-gate 	struct iovec iovs;
74130Sstevel@tonic-gate 	int xpg4 = 0;
74140Sstevel@tonic-gate 
74150Sstevel@tonic-gate 	ASSERT(vp->v_stream);
74160Sstevel@tonic-gate 	stp = vp->v_stream;
74170Sstevel@tonic-gate 	wqp = stp->sd_wrq;
74180Sstevel@tonic-gate 
74190Sstevel@tonic-gate 	/*
74200Sstevel@tonic-gate 	 * If it is an XPG4 application, we need to send
74210Sstevel@tonic-gate 	 * SIGPIPE below
74220Sstevel@tonic-gate 	 */
74230Sstevel@tonic-gate 
74240Sstevel@tonic-gate 	xpg4 = (flag & MSG_XPG4) ? 1 : 0;
74250Sstevel@tonic-gate 	flag &= ~MSG_XPG4;
74260Sstevel@tonic-gate 
74270Sstevel@tonic-gate #ifdef C2_AUDIT
74280Sstevel@tonic-gate 	if (audit_active)
74290Sstevel@tonic-gate 		audit_strputmsg(vp, mctl, mdata, pri, flag, fmode);
74300Sstevel@tonic-gate #endif
74310Sstevel@tonic-gate 
74320Sstevel@tonic-gate 	if (stp->sd_sidp != NULL && stp->sd_vnode->v_type != VFIFO)
74330Sstevel@tonic-gate 		if (error = straccess(stp, JCWRITE))
74340Sstevel@tonic-gate 			return (error);
74350Sstevel@tonic-gate 
74360Sstevel@tonic-gate 	if (stp->sd_flag & (STWRERR|STRHUP|STPLEX)) {
74370Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
74380Sstevel@tonic-gate 		error = strwriteable(stp, B_FALSE, xpg4);
74390Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
74400Sstevel@tonic-gate 		if (error != 0)
74410Sstevel@tonic-gate 			return (error);
74420Sstevel@tonic-gate 	}
74430Sstevel@tonic-gate 
74440Sstevel@tonic-gate 	/*
74450Sstevel@tonic-gate 	 * Check for legal flag value.
74460Sstevel@tonic-gate 	 */
74470Sstevel@tonic-gate 	switch (flag) {
74480Sstevel@tonic-gate 	case MSG_HIPRI:
74490Sstevel@tonic-gate 		if ((mctl->len < 0) || (pri != 0))
74500Sstevel@tonic-gate 			return (EINVAL);
74510Sstevel@tonic-gate 		break;
74520Sstevel@tonic-gate 	case MSG_BAND:
74530Sstevel@tonic-gate 		break;
74540Sstevel@tonic-gate 
74550Sstevel@tonic-gate 	default:
74560Sstevel@tonic-gate 		return (EINVAL);
74570Sstevel@tonic-gate 	}
74580Sstevel@tonic-gate 
74590Sstevel@tonic-gate 	TRACE_1(TR_FAC_STREAMS_FR, TR_STRPUTMSG_IN,
74600Sstevel@tonic-gate 		"strputmsg in:stp %p", stp);
74610Sstevel@tonic-gate 
74620Sstevel@tonic-gate 	/* get these values from those cached in the stream head */
74630Sstevel@tonic-gate 	rmin = stp->sd_qn_minpsz;
74640Sstevel@tonic-gate 	rmax = stp->sd_qn_maxpsz;
74650Sstevel@tonic-gate 
74660Sstevel@tonic-gate 	/*
74670Sstevel@tonic-gate 	 * Make sure ctl and data sizes together fall within the
74680Sstevel@tonic-gate 	 * limits of the max and min receive packet sizes and do
74690Sstevel@tonic-gate 	 * not exceed system limit.
74700Sstevel@tonic-gate 	 */
74710Sstevel@tonic-gate 	ASSERT((rmax >= 0) || (rmax == INFPSZ));
74720Sstevel@tonic-gate 	if (rmax == 0) {
74730Sstevel@tonic-gate 		return (ERANGE);
74740Sstevel@tonic-gate 	}
74750Sstevel@tonic-gate 	/*
74760Sstevel@tonic-gate 	 * Use the MAXIMUM of sd_maxblk and q_maxpsz.
74770Sstevel@tonic-gate 	 * Needed to prevent partial failures in the strmakedata loop.
74780Sstevel@tonic-gate 	 */
74790Sstevel@tonic-gate 	if (stp->sd_maxblk != INFPSZ && rmax != INFPSZ && rmax < stp->sd_maxblk)
74800Sstevel@tonic-gate 		rmax = stp->sd_maxblk;
74810Sstevel@tonic-gate 
74820Sstevel@tonic-gate 	if ((msgsize = mdata->len) < 0) {
74830Sstevel@tonic-gate 		msgsize = 0;
74840Sstevel@tonic-gate 		rmin = 0;	/* no range check for NULL data part */
74850Sstevel@tonic-gate 	}
74860Sstevel@tonic-gate 	if ((msgsize < rmin) ||
74870Sstevel@tonic-gate 	    ((msgsize > rmax) && (rmax != INFPSZ)) ||
74880Sstevel@tonic-gate 	    (mctl->len > strctlsz)) {
74890Sstevel@tonic-gate 		return (ERANGE);
74900Sstevel@tonic-gate 	}
74910Sstevel@tonic-gate 
74920Sstevel@tonic-gate 	/*
74930Sstevel@tonic-gate 	 * Setup uio and iov for data part
74940Sstevel@tonic-gate 	 */
74950Sstevel@tonic-gate 	iovs.iov_base = mdata->buf;
74960Sstevel@tonic-gate 	iovs.iov_len = msgsize;
74970Sstevel@tonic-gate 	uios.uio_iov = &iovs;
74980Sstevel@tonic-gate 	uios.uio_iovcnt = 1;
74990Sstevel@tonic-gate 	uios.uio_loffset = 0;
75000Sstevel@tonic-gate 	uios.uio_segflg = UIO_USERSPACE;
75010Sstevel@tonic-gate 	uios.uio_fmode = fmode;
75020Sstevel@tonic-gate 	uios.uio_extflg = UIO_COPY_DEFAULT;
75030Sstevel@tonic-gate 	uios.uio_resid = msgsize;
75040Sstevel@tonic-gate 	uios.uio_offset = 0;
75050Sstevel@tonic-gate 
75060Sstevel@tonic-gate 	/* Ignore flow control in strput for HIPRI */
75070Sstevel@tonic-gate 	if (flag & MSG_HIPRI)
75080Sstevel@tonic-gate 		flag |= MSG_IGNFLOW;
75090Sstevel@tonic-gate 
75100Sstevel@tonic-gate 	for (;;) {
75110Sstevel@tonic-gate 		int done = 0;
75120Sstevel@tonic-gate 
75130Sstevel@tonic-gate 		/*
75140Sstevel@tonic-gate 		 * strput will always free the ctl mblk - even when strput
75150Sstevel@tonic-gate 		 * fails.
75160Sstevel@tonic-gate 		 */
75170Sstevel@tonic-gate 		if ((error = strmakectl(mctl, flag, fmode, &mp)) != 0) {
75180Sstevel@tonic-gate 			TRACE_3(TR_FAC_STREAMS_FR, TR_STRPUTMSG_OUT,
75190Sstevel@tonic-gate 				"strputmsg out:stp %p out %d error %d",
75200Sstevel@tonic-gate 				stp, 1, error);
75210Sstevel@tonic-gate 			return (error);
75220Sstevel@tonic-gate 		}
75230Sstevel@tonic-gate 		/*
75240Sstevel@tonic-gate 		 * Verify that the whole message can be transferred by
75250Sstevel@tonic-gate 		 * strput.
75260Sstevel@tonic-gate 		 */
75270Sstevel@tonic-gate 		ASSERT(stp->sd_maxblk == INFPSZ ||
75280Sstevel@tonic-gate 			stp->sd_maxblk >= mdata->len);
75290Sstevel@tonic-gate 
75300Sstevel@tonic-gate 		msgsize = mdata->len;
75310Sstevel@tonic-gate 		error = strput(stp, mp, uiop, &msgsize, 0, pri, flag);
75320Sstevel@tonic-gate 		mdata->len = msgsize;
75330Sstevel@tonic-gate 
75340Sstevel@tonic-gate 		if (error == 0)
75350Sstevel@tonic-gate 			break;
75360Sstevel@tonic-gate 
75370Sstevel@tonic-gate 		if (error != EWOULDBLOCK)
75380Sstevel@tonic-gate 			goto out;
75390Sstevel@tonic-gate 
75400Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
75410Sstevel@tonic-gate 		/*
75420Sstevel@tonic-gate 		 * Check for a missed wakeup.
75430Sstevel@tonic-gate 		 * Needed since strput did not hold sd_lock across
75440Sstevel@tonic-gate 		 * the canputnext.
75450Sstevel@tonic-gate 		 */
75460Sstevel@tonic-gate 		if (bcanputnext(wqp, pri)) {
75470Sstevel@tonic-gate 			/* Try again */
75480Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
75490Sstevel@tonic-gate 			continue;
75500Sstevel@tonic-gate 		}
75510Sstevel@tonic-gate 		TRACE_2(TR_FAC_STREAMS_FR, TR_STRPUTMSG_WAIT,
75520Sstevel@tonic-gate 			"strputmsg wait:stp %p waits pri %d", stp, pri);
75530Sstevel@tonic-gate 		if (((error = strwaitq(stp, WRITEWAIT, (ssize_t)0, fmode, -1,
75540Sstevel@tonic-gate 		    &done)) != 0) || done) {
75550Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
75560Sstevel@tonic-gate 			TRACE_3(TR_FAC_STREAMS_FR, TR_STRPUTMSG_OUT,
75570Sstevel@tonic-gate 				"strputmsg out:q %p out %d error %d",
75580Sstevel@tonic-gate 				stp, 0, error);
75590Sstevel@tonic-gate 			return (error);
75600Sstevel@tonic-gate 		}
75610Sstevel@tonic-gate 		TRACE_1(TR_FAC_STREAMS_FR, TR_STRPUTMSG_WAKE,
75620Sstevel@tonic-gate 			"strputmsg wake:stp %p wakes", stp);
75630Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
75640Sstevel@tonic-gate 		if (stp->sd_sidp != NULL && stp->sd_vnode->v_type != VFIFO)
75650Sstevel@tonic-gate 			if (error = straccess(stp, JCWRITE))
75660Sstevel@tonic-gate 				return (error);
75670Sstevel@tonic-gate 	}
75680Sstevel@tonic-gate out:
75690Sstevel@tonic-gate 	/*
75700Sstevel@tonic-gate 	 * For historic reasons, applications expect EAGAIN
75710Sstevel@tonic-gate 	 * when data mblk could not be allocated. so change
75720Sstevel@tonic-gate 	 * ENOMEM back to EAGAIN
75730Sstevel@tonic-gate 	 */
75740Sstevel@tonic-gate 	if (error == ENOMEM)
75750Sstevel@tonic-gate 		error = EAGAIN;
75760Sstevel@tonic-gate 	TRACE_3(TR_FAC_STREAMS_FR, TR_STRPUTMSG_OUT,
75770Sstevel@tonic-gate 		"strputmsg out:stp %p out %d error %d", stp, 2, error);
75780Sstevel@tonic-gate 	return (error);
75790Sstevel@tonic-gate }
75800Sstevel@tonic-gate 
75810Sstevel@tonic-gate /*
75820Sstevel@tonic-gate  * Put a message downstream.
75830Sstevel@tonic-gate  * Can send only an M_PROTO/M_PCPROTO by passing in a NULL uiop.
75840Sstevel@tonic-gate  * The fmode flag (NDELAY, NONBLOCK) is the or of the flags in the uio
75850Sstevel@tonic-gate  * and the fmode parameter.
75860Sstevel@tonic-gate  *
75870Sstevel@tonic-gate  * This routine handles the consolidation private flags:
75880Sstevel@tonic-gate  *	MSG_IGNERROR	Ignore any stream head error except STPLEX.
75890Sstevel@tonic-gate  *	MSG_HOLDSIG	Hold signals while waiting for data.
75900Sstevel@tonic-gate  *	MSG_IGNFLOW	Don't check streams flow control.
75910Sstevel@tonic-gate  *
75920Sstevel@tonic-gate  * NOTE: strputmsg and kstrputmsg have much of the logic in common.
75930Sstevel@tonic-gate  */
75940Sstevel@tonic-gate int
75950Sstevel@tonic-gate kstrputmsg(
75960Sstevel@tonic-gate 	struct vnode *vp,
75970Sstevel@tonic-gate 	mblk_t *mctl,
75980Sstevel@tonic-gate 	struct uio *uiop,
75990Sstevel@tonic-gate 	ssize_t msgsize,
76000Sstevel@tonic-gate 	unsigned char pri,
76010Sstevel@tonic-gate 	int flag,
76020Sstevel@tonic-gate 	int fmode)
76030Sstevel@tonic-gate {
76040Sstevel@tonic-gate 	struct stdata *stp;
76050Sstevel@tonic-gate 	queue_t *wqp;
76060Sstevel@tonic-gate 	ssize_t rmin, rmax;
76070Sstevel@tonic-gate 	int error;
76080Sstevel@tonic-gate 
76090Sstevel@tonic-gate 	ASSERT(vp->v_stream);
76100Sstevel@tonic-gate 	stp = vp->v_stream;
76110Sstevel@tonic-gate 	wqp = stp->sd_wrq;
76120Sstevel@tonic-gate #ifdef C2_AUDIT
76130Sstevel@tonic-gate 	if (audit_active)
76140Sstevel@tonic-gate 		audit_strputmsg(vp, NULL, NULL, pri, flag, fmode);
76150Sstevel@tonic-gate #endif
7616577Smeem 	if (mctl == NULL)
7617577Smeem 		return (EINVAL);
76180Sstevel@tonic-gate 
76190Sstevel@tonic-gate 	if (stp->sd_sidp != NULL && stp->sd_vnode->v_type != VFIFO) {
76200Sstevel@tonic-gate 		if (error = straccess(stp, JCWRITE)) {
76210Sstevel@tonic-gate 			freemsg(mctl);
76220Sstevel@tonic-gate 			return (error);
76230Sstevel@tonic-gate 		}
76240Sstevel@tonic-gate 	}
76250Sstevel@tonic-gate 
76260Sstevel@tonic-gate 	if ((stp->sd_flag & STPLEX) || !(flag & MSG_IGNERROR)) {
76270Sstevel@tonic-gate 		if (stp->sd_flag & (STWRERR|STRHUP|STPLEX)) {
76280Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
76290Sstevel@tonic-gate 			error = strwriteable(stp, B_FALSE, B_TRUE);
76300Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
76310Sstevel@tonic-gate 			if (error != 0) {
76320Sstevel@tonic-gate 				freemsg(mctl);
76330Sstevel@tonic-gate 				return (error);
76340Sstevel@tonic-gate 			}
76350Sstevel@tonic-gate 		}
76360Sstevel@tonic-gate 	}
76370Sstevel@tonic-gate 
76380Sstevel@tonic-gate 	/*
76390Sstevel@tonic-gate 	 * Check for legal flag value.
76400Sstevel@tonic-gate 	 */
76410Sstevel@tonic-gate 	switch (flag & (MSG_HIPRI|MSG_BAND|MSG_ANY)) {
76420Sstevel@tonic-gate 	case MSG_HIPRI:
7643577Smeem 		if (pri != 0) {
76440Sstevel@tonic-gate 			freemsg(mctl);
76450Sstevel@tonic-gate 			return (EINVAL);
76460Sstevel@tonic-gate 		}
76470Sstevel@tonic-gate 		break;
76480Sstevel@tonic-gate 	case MSG_BAND:
76490Sstevel@tonic-gate 		break;
76500Sstevel@tonic-gate 	default:
76510Sstevel@tonic-gate 		freemsg(mctl);
76520Sstevel@tonic-gate 		return (EINVAL);
76530Sstevel@tonic-gate 	}
76540Sstevel@tonic-gate 
76550Sstevel@tonic-gate 	TRACE_1(TR_FAC_STREAMS_FR, TR_KSTRPUTMSG_IN,
76560Sstevel@tonic-gate 		"kstrputmsg in:stp %p", stp);
76570Sstevel@tonic-gate 
76580Sstevel@tonic-gate 	/* get these values from those cached in the stream head */
76590Sstevel@tonic-gate 	rmin = stp->sd_qn_minpsz;
76600Sstevel@tonic-gate 	rmax = stp->sd_qn_maxpsz;
76610Sstevel@tonic-gate 
76620Sstevel@tonic-gate 	/*
76630Sstevel@tonic-gate 	 * Make sure ctl and data sizes together fall within the
76640Sstevel@tonic-gate 	 * limits of the max and min receive packet sizes and do
76650Sstevel@tonic-gate 	 * not exceed system limit.
76660Sstevel@tonic-gate 	 */
76670Sstevel@tonic-gate 	ASSERT((rmax >= 0) || (rmax == INFPSZ));
76680Sstevel@tonic-gate 	if (rmax == 0) {
76690Sstevel@tonic-gate 		freemsg(mctl);
76700Sstevel@tonic-gate 		return (ERANGE);
76710Sstevel@tonic-gate 	}
76720Sstevel@tonic-gate 	/*
76730Sstevel@tonic-gate 	 * Use the MAXIMUM of sd_maxblk and q_maxpsz.
76740Sstevel@tonic-gate 	 * Needed to prevent partial failures in the strmakedata loop.
76750Sstevel@tonic-gate 	 */
76760Sstevel@tonic-gate 	if (stp->sd_maxblk != INFPSZ && rmax != INFPSZ && rmax < stp->sd_maxblk)
76770Sstevel@tonic-gate 		rmax = stp->sd_maxblk;
76780Sstevel@tonic-gate 
76790Sstevel@tonic-gate 	if (uiop == NULL) {
76800Sstevel@tonic-gate 		msgsize = -1;
76810Sstevel@tonic-gate 		rmin = -1;	/* no range check for NULL data part */
76820Sstevel@tonic-gate 	} else {
76830Sstevel@tonic-gate 		/* Use uio flags as well as the fmode parameter flags */
76840Sstevel@tonic-gate 		fmode |= uiop->uio_fmode;
76850Sstevel@tonic-gate 
76860Sstevel@tonic-gate 		if ((msgsize < rmin) ||
76870Sstevel@tonic-gate 		    ((msgsize > rmax) && (rmax != INFPSZ))) {
76880Sstevel@tonic-gate 			freemsg(mctl);
76890Sstevel@tonic-gate 			return (ERANGE);
76900Sstevel@tonic-gate 		}
76910Sstevel@tonic-gate 	}
76920Sstevel@tonic-gate 
76930Sstevel@tonic-gate 	/* Ignore flow control in strput for HIPRI */
76940Sstevel@tonic-gate 	if (flag & MSG_HIPRI)
76950Sstevel@tonic-gate 		flag |= MSG_IGNFLOW;
76960Sstevel@tonic-gate 
76970Sstevel@tonic-gate 	for (;;) {
76980Sstevel@tonic-gate 		int done = 0;
76990Sstevel@tonic-gate 		int waitflag;
77000Sstevel@tonic-gate 		mblk_t *mp;
77010Sstevel@tonic-gate 
77020Sstevel@tonic-gate 		/*
77030Sstevel@tonic-gate 		 * strput will always free the ctl mblk - even when strput
77040Sstevel@tonic-gate 		 * fails. If MSG_IGNFLOW is set then any error returned
77050Sstevel@tonic-gate 		 * will cause us to break the loop, so we don't need a copy
77060Sstevel@tonic-gate 		 * of the message. If MSG_IGNFLOW is not set, then we can
77070Sstevel@tonic-gate 		 * get hit by flow control and be forced to try again. In
77080Sstevel@tonic-gate 		 * this case we need to have a copy of the message. We
77090Sstevel@tonic-gate 		 * do this using copymsg since the message may get modified
77100Sstevel@tonic-gate 		 * by something below us.
77110Sstevel@tonic-gate 		 *
77120Sstevel@tonic-gate 		 * We've observed that many TPI providers do not check db_ref
77130Sstevel@tonic-gate 		 * on the control messages but blindly reuse them for the
77140Sstevel@tonic-gate 		 * T_OK_ACK/T_ERROR_ACK. Thus using copymsg is more
77150Sstevel@tonic-gate 		 * friendly to such providers than using dupmsg. Also, note
77160Sstevel@tonic-gate 		 * that sockfs uses MSG_IGNFLOW for all TPI control messages.
77170Sstevel@tonic-gate 		 * Only data messages are subject to flow control, hence
77180Sstevel@tonic-gate 		 * subject to this copymsg.
77190Sstevel@tonic-gate 		 */
77200Sstevel@tonic-gate 		if (flag & MSG_IGNFLOW) {
77210Sstevel@tonic-gate 			mp = mctl;
77220Sstevel@tonic-gate 			mctl = NULL;
77230Sstevel@tonic-gate 		} else {
77240Sstevel@tonic-gate 			do {
77250Sstevel@tonic-gate 				/*
77260Sstevel@tonic-gate 				 * If a message has a free pointer, the message
77270Sstevel@tonic-gate 				 * must be dupmsg to maintain this pointer.
77280Sstevel@tonic-gate 				 * Code using this facility must be sure
77290Sstevel@tonic-gate 				 * that modules below will not change the
77300Sstevel@tonic-gate 				 * contents of the dblk without checking db_ref
77310Sstevel@tonic-gate 				 * first. If db_ref is > 1, then the module
77320Sstevel@tonic-gate 				 * needs to do a copymsg first. Otherwise,
77330Sstevel@tonic-gate 				 * the contents of the dblk may become
77340Sstevel@tonic-gate 				 * inconsistent because the freesmg/freeb below
77350Sstevel@tonic-gate 				 * may end up calling atomic_add_32_nv.
77360Sstevel@tonic-gate 				 * The atomic_add_32_nv in freeb (accessing
77370Sstevel@tonic-gate 				 * all of db_ref, db_type, db_flags, and
77380Sstevel@tonic-gate 				 * db_struioflag) does not prevent other threads
77390Sstevel@tonic-gate 				 * from concurrently trying to modify e.g.
77400Sstevel@tonic-gate 				 * db_type.
77410Sstevel@tonic-gate 				 */
77420Sstevel@tonic-gate 				if (mctl->b_datap->db_frtnp != NULL)
77430Sstevel@tonic-gate 					mp = dupmsg(mctl);
77440Sstevel@tonic-gate 				else
77450Sstevel@tonic-gate 					mp = copymsg(mctl);
77460Sstevel@tonic-gate 
7747577Smeem 				if (mp != NULL)
77480Sstevel@tonic-gate 					break;
77490Sstevel@tonic-gate 
77500Sstevel@tonic-gate 				error = strwaitbuf(msgdsize(mctl), BPRI_MED);
77510Sstevel@tonic-gate 				if (error) {
77520Sstevel@tonic-gate 					freemsg(mctl);
77530Sstevel@tonic-gate 					return (error);
77540Sstevel@tonic-gate 				}
77550Sstevel@tonic-gate 			} while (mp == NULL);
77560Sstevel@tonic-gate 		}
77570Sstevel@tonic-gate 		/*
77580Sstevel@tonic-gate 		 * Verify that all of msgsize can be transferred by
77590Sstevel@tonic-gate 		 * strput.
77600Sstevel@tonic-gate 		 */
7761577Smeem 		ASSERT(stp->sd_maxblk == INFPSZ || stp->sd_maxblk >= msgsize);
77620Sstevel@tonic-gate 		error = strput(stp, mp, uiop, &msgsize, 0, pri, flag);
77630Sstevel@tonic-gate 		if (error == 0)
77640Sstevel@tonic-gate 			break;
77650Sstevel@tonic-gate 
77660Sstevel@tonic-gate 		if (error != EWOULDBLOCK)
77670Sstevel@tonic-gate 			goto out;
77680Sstevel@tonic-gate 
77690Sstevel@tonic-gate 		/*
77700Sstevel@tonic-gate 		 * IF MSG_IGNFLOW is set we should have broken out of loop
77710Sstevel@tonic-gate 		 * above.
77720Sstevel@tonic-gate 		 */
77730Sstevel@tonic-gate 		ASSERT(!(flag & MSG_IGNFLOW));
77740Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
77750Sstevel@tonic-gate 		/*
77760Sstevel@tonic-gate 		 * Check for a missed wakeup.
77770Sstevel@tonic-gate 		 * Needed since strput did not hold sd_lock across
77780Sstevel@tonic-gate 		 * the canputnext.
77790Sstevel@tonic-gate 		 */
77800Sstevel@tonic-gate 		if (bcanputnext(wqp, pri)) {
77810Sstevel@tonic-gate 			/* Try again */
77820Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
77830Sstevel@tonic-gate 			continue;
77840Sstevel@tonic-gate 		}
77850Sstevel@tonic-gate 		TRACE_2(TR_FAC_STREAMS_FR, TR_KSTRPUTMSG_WAIT,
77860Sstevel@tonic-gate 			"kstrputmsg wait:stp %p waits pri %d", stp, pri);
77870Sstevel@tonic-gate 
77880Sstevel@tonic-gate 		waitflag = WRITEWAIT;
77890Sstevel@tonic-gate 		if (flag & (MSG_HOLDSIG|MSG_IGNERROR)) {
77900Sstevel@tonic-gate 			if (flag & MSG_HOLDSIG)
77910Sstevel@tonic-gate 				waitflag |= STR_NOSIG;
77920Sstevel@tonic-gate 			if (flag & MSG_IGNERROR)
77930Sstevel@tonic-gate 				waitflag |= STR_NOERROR;
77940Sstevel@tonic-gate 		}
77950Sstevel@tonic-gate 		if (((error = strwaitq(stp, waitflag,
77960Sstevel@tonic-gate 		    (ssize_t)0, fmode, -1, &done)) != 0) || done) {
77970Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
77980Sstevel@tonic-gate 			TRACE_3(TR_FAC_STREAMS_FR, TR_KSTRPUTMSG_OUT,
77990Sstevel@tonic-gate 				"kstrputmsg out:stp %p out %d error %d",
78000Sstevel@tonic-gate 				stp, 0, error);
78010Sstevel@tonic-gate 			freemsg(mctl);
78020Sstevel@tonic-gate 			return (error);
78030Sstevel@tonic-gate 		}
78040Sstevel@tonic-gate 		TRACE_1(TR_FAC_STREAMS_FR, TR_KSTRPUTMSG_WAKE,
78050Sstevel@tonic-gate 			"kstrputmsg wake:stp %p wakes", stp);
78060Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
78070Sstevel@tonic-gate 		if (stp->sd_sidp != NULL && stp->sd_vnode->v_type != VFIFO) {
78080Sstevel@tonic-gate 			if (error = straccess(stp, JCWRITE)) {
78090Sstevel@tonic-gate 				freemsg(mctl);
78100Sstevel@tonic-gate 				return (error);
78110Sstevel@tonic-gate 			}
78120Sstevel@tonic-gate 		}
78130Sstevel@tonic-gate 	}
78140Sstevel@tonic-gate out:
78150Sstevel@tonic-gate 	freemsg(mctl);
78160Sstevel@tonic-gate 	/*
78170Sstevel@tonic-gate 	 * For historic reasons, applications expect EAGAIN
78180Sstevel@tonic-gate 	 * when data mblk could not be allocated. so change
78190Sstevel@tonic-gate 	 * ENOMEM back to EAGAIN
78200Sstevel@tonic-gate 	 */
78210Sstevel@tonic-gate 	if (error == ENOMEM)
78220Sstevel@tonic-gate 		error = EAGAIN;
78230Sstevel@tonic-gate 	TRACE_3(TR_FAC_STREAMS_FR, TR_KSTRPUTMSG_OUT,
78240Sstevel@tonic-gate 		"kstrputmsg out:stp %p out %d error %d", stp, 2, error);
78250Sstevel@tonic-gate 	return (error);
78260Sstevel@tonic-gate }
78270Sstevel@tonic-gate 
78280Sstevel@tonic-gate /*
78290Sstevel@tonic-gate  * Determines whether the necessary conditions are set on a stream
78300Sstevel@tonic-gate  * for it to be readable, writeable, or have exceptions.
78310Sstevel@tonic-gate  *
78320Sstevel@tonic-gate  * strpoll handles the consolidation private events:
78330Sstevel@tonic-gate  *	POLLNOERR	Do not return POLLERR even if there are stream
78340Sstevel@tonic-gate  *			head errors.
78350Sstevel@tonic-gate  *			Used by sockfs.
78360Sstevel@tonic-gate  *	POLLRDDATA	Do not return POLLIN unless at least one message on
78370Sstevel@tonic-gate  *			the queue contains one or more M_DATA mblks. Thus
78380Sstevel@tonic-gate  *			when this flag is set a queue with only
78390Sstevel@tonic-gate  *			M_PROTO/M_PCPROTO mblks does not return POLLIN.
78400Sstevel@tonic-gate  *			Used by sockfs to ignore T_EXDATA_IND messages.
78410Sstevel@tonic-gate  *
78420Sstevel@tonic-gate  * Note: POLLRDDATA assumes that synch streams only return messages with
78430Sstevel@tonic-gate  * an M_DATA attached (i.e. not messages consisting of only
78440Sstevel@tonic-gate  * an M_PROTO/M_PCPROTO part).
78450Sstevel@tonic-gate  */
78460Sstevel@tonic-gate int
78470Sstevel@tonic-gate strpoll(
78480Sstevel@tonic-gate 	struct stdata *stp,
78490Sstevel@tonic-gate 	short events_arg,
78500Sstevel@tonic-gate 	int anyyet,
78510Sstevel@tonic-gate 	short *reventsp,
78520Sstevel@tonic-gate 	struct pollhead **phpp)
78530Sstevel@tonic-gate {
78540Sstevel@tonic-gate 	int events = (ushort_t)events_arg;
78550Sstevel@tonic-gate 	int retevents = 0;
78560Sstevel@tonic-gate 	mblk_t *mp;
78570Sstevel@tonic-gate 	qband_t *qbp;
78580Sstevel@tonic-gate 	long sd_flags = stp->sd_flag;
78590Sstevel@tonic-gate 	int headlocked = 0;
78600Sstevel@tonic-gate 
78610Sstevel@tonic-gate 	/*
78620Sstevel@tonic-gate 	 * For performance, a single 'if' tests for most possible edge
78630Sstevel@tonic-gate 	 * conditions in one shot
78640Sstevel@tonic-gate 	 */
78650Sstevel@tonic-gate 	if (sd_flags & (STPLEX | STRDERR | STWRERR)) {
78660Sstevel@tonic-gate 		if (sd_flags & STPLEX) {
78670Sstevel@tonic-gate 			*reventsp = POLLNVAL;
78680Sstevel@tonic-gate 			return (EINVAL);
78690Sstevel@tonic-gate 		}
78700Sstevel@tonic-gate 		if (((events & (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)) &&
78710Sstevel@tonic-gate 		    (sd_flags & STRDERR)) ||
78720Sstevel@tonic-gate 		    ((events & (POLLOUT | POLLWRNORM | POLLWRBAND)) &&
78730Sstevel@tonic-gate 		    (sd_flags & STWRERR))) {
78740Sstevel@tonic-gate 			if (!(events & POLLNOERR)) {
78750Sstevel@tonic-gate 				*reventsp = POLLERR;
78760Sstevel@tonic-gate 				return (0);
78770Sstevel@tonic-gate 			}
78780Sstevel@tonic-gate 		}
78790Sstevel@tonic-gate 	}
78800Sstevel@tonic-gate 	if (sd_flags & STRHUP) {
78810Sstevel@tonic-gate 		retevents |= POLLHUP;
78820Sstevel@tonic-gate 	} else if (events & (POLLWRNORM | POLLWRBAND)) {
78830Sstevel@tonic-gate 		queue_t *tq;
78840Sstevel@tonic-gate 		queue_t	*qp = stp->sd_wrq;
78850Sstevel@tonic-gate 
78860Sstevel@tonic-gate 		claimstr(qp);
78870Sstevel@tonic-gate 		/* Find next module forward that has a service procedure */
78880Sstevel@tonic-gate 		tq = qp->q_next->q_nfsrv;
78890Sstevel@tonic-gate 		ASSERT(tq != NULL);
78900Sstevel@tonic-gate 
78910Sstevel@tonic-gate 		polllock(&stp->sd_pollist, QLOCK(tq));
78920Sstevel@tonic-gate 		if (events & POLLWRNORM) {
78930Sstevel@tonic-gate 			queue_t *sqp;
78940Sstevel@tonic-gate 
78950Sstevel@tonic-gate 			if (tq->q_flag & QFULL)
78960Sstevel@tonic-gate 				/* ensure backq svc procedure runs */
78970Sstevel@tonic-gate 				tq->q_flag |= QWANTW;
78980Sstevel@tonic-gate 			else if ((sqp = stp->sd_struiowrq) != NULL) {
78990Sstevel@tonic-gate 				/* Check sync stream barrier write q */
79000Sstevel@tonic-gate 				mutex_exit(QLOCK(tq));
79010Sstevel@tonic-gate 				polllock(&stp->sd_pollist, QLOCK(sqp));
79020Sstevel@tonic-gate 				if (sqp->q_flag & QFULL)
79030Sstevel@tonic-gate 					/* ensure pollwakeup() is done */
79040Sstevel@tonic-gate 					sqp->q_flag |= QWANTWSYNC;
79050Sstevel@tonic-gate 				else
79060Sstevel@tonic-gate 					retevents |= POLLOUT;
79070Sstevel@tonic-gate 				/* More write events to process ??? */
79080Sstevel@tonic-gate 				if (! (events & POLLWRBAND)) {
79090Sstevel@tonic-gate 					mutex_exit(QLOCK(sqp));
79100Sstevel@tonic-gate 					releasestr(qp);
79110Sstevel@tonic-gate 					goto chkrd;
79120Sstevel@tonic-gate 				}
79130Sstevel@tonic-gate 				mutex_exit(QLOCK(sqp));
79140Sstevel@tonic-gate 				polllock(&stp->sd_pollist, QLOCK(tq));
79150Sstevel@tonic-gate 			} else
79160Sstevel@tonic-gate 				retevents |= POLLOUT;
79170Sstevel@tonic-gate 		}
79180Sstevel@tonic-gate 		if (events & POLLWRBAND) {
79190Sstevel@tonic-gate 			qbp = tq->q_bandp;
79200Sstevel@tonic-gate 			if (qbp) {
79210Sstevel@tonic-gate 				while (qbp) {
79220Sstevel@tonic-gate 					if (qbp->qb_flag & QB_FULL)
79230Sstevel@tonic-gate 						qbp->qb_flag |= QB_WANTW;
79240Sstevel@tonic-gate 					else
79250Sstevel@tonic-gate 						retevents |= POLLWRBAND;
79260Sstevel@tonic-gate 					qbp = qbp->qb_next;
79270Sstevel@tonic-gate 				}
79280Sstevel@tonic-gate 			} else {
79290Sstevel@tonic-gate 				retevents |= POLLWRBAND;
79300Sstevel@tonic-gate 			}
79310Sstevel@tonic-gate 		}
79320Sstevel@tonic-gate 		mutex_exit(QLOCK(tq));
79330Sstevel@tonic-gate 		releasestr(qp);
79340Sstevel@tonic-gate 	}
79350Sstevel@tonic-gate chkrd:
79360Sstevel@tonic-gate 	if (sd_flags & STRPRI) {
79370Sstevel@tonic-gate 		retevents |= (events & POLLPRI);
79380Sstevel@tonic-gate 	} else if (events & (POLLRDNORM | POLLRDBAND | POLLIN)) {
79390Sstevel@tonic-gate 		queue_t	*qp = _RD(stp->sd_wrq);
79400Sstevel@tonic-gate 		int normevents = (events & (POLLIN | POLLRDNORM));
79410Sstevel@tonic-gate 
79420Sstevel@tonic-gate 		/*
79430Sstevel@tonic-gate 		 * Note: Need to do polllock() here since ps_lock may be
79440Sstevel@tonic-gate 		 * held. See bug 4191544.
79450Sstevel@tonic-gate 		 */
79460Sstevel@tonic-gate 		polllock(&stp->sd_pollist, &stp->sd_lock);
79470Sstevel@tonic-gate 		headlocked = 1;
79480Sstevel@tonic-gate 		mp = qp->q_first;
79490Sstevel@tonic-gate 		while (mp) {
79500Sstevel@tonic-gate 			/*
79510Sstevel@tonic-gate 			 * For POLLRDDATA we scan b_cont and b_next until we
79520Sstevel@tonic-gate 			 * find an M_DATA.
79530Sstevel@tonic-gate 			 */
79540Sstevel@tonic-gate 			if ((events & POLLRDDATA) &&
79550Sstevel@tonic-gate 			    mp->b_datap->db_type != M_DATA) {
79560Sstevel@tonic-gate 				mblk_t *nmp = mp->b_cont;
79570Sstevel@tonic-gate 
79580Sstevel@tonic-gate 				while (nmp != NULL &&
79590Sstevel@tonic-gate 				    nmp->b_datap->db_type != M_DATA)
79600Sstevel@tonic-gate 					nmp = nmp->b_cont;
79610Sstevel@tonic-gate 				if (nmp == NULL) {
79620Sstevel@tonic-gate 					mp = mp->b_next;
79630Sstevel@tonic-gate 					continue;
79640Sstevel@tonic-gate 				}
79650Sstevel@tonic-gate 			}
79660Sstevel@tonic-gate 			if (mp->b_band == 0)
79670Sstevel@tonic-gate 				retevents |= normevents;
79680Sstevel@tonic-gate 			else
79690Sstevel@tonic-gate 				retevents |= (events & (POLLIN | POLLRDBAND));
79700Sstevel@tonic-gate 			break;
79710Sstevel@tonic-gate 		}
79720Sstevel@tonic-gate 		if (! (retevents & normevents) &&
79730Sstevel@tonic-gate 		    (stp->sd_wakeq & RSLEEP)) {
79740Sstevel@tonic-gate 			/*
79750Sstevel@tonic-gate 			 * Sync stream barrier read queue has data.
79760Sstevel@tonic-gate 			 */
79770Sstevel@tonic-gate 			retevents |= normevents;
79780Sstevel@tonic-gate 		}
79790Sstevel@tonic-gate 		/* Treat eof as normal data */
79800Sstevel@tonic-gate 		if (sd_flags & STREOF)
79810Sstevel@tonic-gate 			retevents |= normevents;
79820Sstevel@tonic-gate 	}
79830Sstevel@tonic-gate 
79840Sstevel@tonic-gate 	*reventsp = (short)retevents;
79850Sstevel@tonic-gate 	if (retevents) {
79860Sstevel@tonic-gate 		if (headlocked)
79870Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
79880Sstevel@tonic-gate 		return (0);
79890Sstevel@tonic-gate 	}
79900Sstevel@tonic-gate 
79910Sstevel@tonic-gate 	/*
79920Sstevel@tonic-gate 	 * If poll() has not found any events yet, set up event cell
79930Sstevel@tonic-gate 	 * to wake up the poll if a requested event occurs on this
79940Sstevel@tonic-gate 	 * stream.  Check for collisions with outstanding poll requests.
79950Sstevel@tonic-gate 	 */
79960Sstevel@tonic-gate 	if (!anyyet) {
79970Sstevel@tonic-gate 		*phpp = &stp->sd_pollist;
79980Sstevel@tonic-gate 		if (headlocked == 0) {
79990Sstevel@tonic-gate 			polllock(&stp->sd_pollist, &stp->sd_lock);
80000Sstevel@tonic-gate 			headlocked = 1;
80010Sstevel@tonic-gate 		}
80020Sstevel@tonic-gate 		stp->sd_rput_opt |= SR_POLLIN;
80030Sstevel@tonic-gate 	}
80040Sstevel@tonic-gate 	if (headlocked)
80050Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
80060Sstevel@tonic-gate 	return (0);
80070Sstevel@tonic-gate }
80080Sstevel@tonic-gate 
80090Sstevel@tonic-gate /*
80100Sstevel@tonic-gate  * The purpose of putback() is to assure sleeping polls/reads
80110Sstevel@tonic-gate  * are awakened when there are no new messages arriving at the,
80120Sstevel@tonic-gate  * stream head, and a message is placed back on the read queue.
80130Sstevel@tonic-gate  *
80140Sstevel@tonic-gate  * sd_lock must be held when messages are placed back on stream
80150Sstevel@tonic-gate  * head.  (getq() holds sd_lock when it removes messages from
80160Sstevel@tonic-gate  * the queue)
80170Sstevel@tonic-gate  */
80180Sstevel@tonic-gate 
80190Sstevel@tonic-gate static void
80200Sstevel@tonic-gate putback(struct stdata *stp, queue_t *q, mblk_t *bp, int band)
80210Sstevel@tonic-gate {
80220Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&stp->sd_lock));
80230Sstevel@tonic-gate 	(void) putbq(q, bp);
80240Sstevel@tonic-gate 	/*
80250Sstevel@tonic-gate 	 * A message may have come in when the sd_lock was dropped in the
80260Sstevel@tonic-gate 	 * calling routine. If this is the case and STR*ATMARK info was
80270Sstevel@tonic-gate 	 * received, need to move that from the stream head to the q_last
80280Sstevel@tonic-gate 	 * so that SIOCATMARK can return the proper value.
80290Sstevel@tonic-gate 	 */
80300Sstevel@tonic-gate 	if (stp->sd_flag & (STRATMARK | STRNOTATMARK)) {
80310Sstevel@tonic-gate 		unsigned short *flagp = &q->q_last->b_flag;
80320Sstevel@tonic-gate 		uint_t b_flag = (uint_t)*flagp;
80330Sstevel@tonic-gate 
80340Sstevel@tonic-gate 		if (stp->sd_flag & STRATMARK) {
80350Sstevel@tonic-gate 			b_flag &= ~MSGNOTMARKNEXT;
80360Sstevel@tonic-gate 			b_flag |= MSGMARKNEXT;
80370Sstevel@tonic-gate 			stp->sd_flag &= ~STRATMARK;
80380Sstevel@tonic-gate 		} else {
80390Sstevel@tonic-gate 			b_flag &= ~MSGMARKNEXT;
80400Sstevel@tonic-gate 			b_flag |= MSGNOTMARKNEXT;
80410Sstevel@tonic-gate 			stp->sd_flag &= ~STRNOTATMARK;
80420Sstevel@tonic-gate 		}
80430Sstevel@tonic-gate 		*flagp = (unsigned short) b_flag;
80440Sstevel@tonic-gate 	}
80450Sstevel@tonic-gate 
80460Sstevel@tonic-gate #ifdef	DEBUG
80470Sstevel@tonic-gate 	/*
80480Sstevel@tonic-gate 	 * Make sure that the flags are not messed up.
80490Sstevel@tonic-gate 	 */
80500Sstevel@tonic-gate 	{
80510Sstevel@tonic-gate 		mblk_t *mp;
80520Sstevel@tonic-gate 		mp = q->q_last;
80530Sstevel@tonic-gate 		while (mp != NULL) {
80540Sstevel@tonic-gate 			ASSERT((mp->b_flag & (MSGMARKNEXT|MSGNOTMARKNEXT)) !=
80550Sstevel@tonic-gate 			    (MSGMARKNEXT|MSGNOTMARKNEXT));
80560Sstevel@tonic-gate 			mp = mp->b_cont;
80570Sstevel@tonic-gate 		}
80580Sstevel@tonic-gate 	}
80590Sstevel@tonic-gate #endif
80600Sstevel@tonic-gate 	if (q->q_first == bp) {
80610Sstevel@tonic-gate 		short pollevents;
80620Sstevel@tonic-gate 
80630Sstevel@tonic-gate 		if (stp->sd_flag & RSLEEP) {
80640Sstevel@tonic-gate 			stp->sd_flag &= ~RSLEEP;
80650Sstevel@tonic-gate 			cv_broadcast(&q->q_wait);
80660Sstevel@tonic-gate 		}
80670Sstevel@tonic-gate 		if (stp->sd_flag & STRPRI) {
80680Sstevel@tonic-gate 			pollevents = POLLPRI;
80690Sstevel@tonic-gate 		} else {
80700Sstevel@tonic-gate 			if (band == 0) {
80710Sstevel@tonic-gate 				if (!(stp->sd_rput_opt & SR_POLLIN))
80720Sstevel@tonic-gate 					return;
80730Sstevel@tonic-gate 				stp->sd_rput_opt &= ~SR_POLLIN;
80740Sstevel@tonic-gate 				pollevents = POLLIN | POLLRDNORM;
80750Sstevel@tonic-gate 			} else {
80760Sstevel@tonic-gate 				pollevents = POLLIN | POLLRDBAND;
80770Sstevel@tonic-gate 			}
80780Sstevel@tonic-gate 		}
80790Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
80800Sstevel@tonic-gate 		pollwakeup(&stp->sd_pollist, pollevents);
80810Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
80820Sstevel@tonic-gate 	}
80830Sstevel@tonic-gate }
80840Sstevel@tonic-gate 
80850Sstevel@tonic-gate /*
80860Sstevel@tonic-gate  * Return the held vnode attached to the stream head of a
80870Sstevel@tonic-gate  * given queue
80880Sstevel@tonic-gate  * It is the responsibility of the calling routine to ensure
80890Sstevel@tonic-gate  * that the queue does not go away (e.g. pop).
80900Sstevel@tonic-gate  */
80910Sstevel@tonic-gate vnode_t *
80920Sstevel@tonic-gate strq2vp(queue_t *qp)
80930Sstevel@tonic-gate {
80940Sstevel@tonic-gate 	vnode_t *vp;
80950Sstevel@tonic-gate 	vp = STREAM(qp)->sd_vnode;
80960Sstevel@tonic-gate 	ASSERT(vp != NULL);
80970Sstevel@tonic-gate 	VN_HOLD(vp);
80980Sstevel@tonic-gate 	return (vp);
80990Sstevel@tonic-gate }
81000Sstevel@tonic-gate 
81010Sstevel@tonic-gate /*
81020Sstevel@tonic-gate  * return the stream head write queue for the given vp
81030Sstevel@tonic-gate  * It is the responsibility of the calling routine to ensure
81040Sstevel@tonic-gate  * that the stream or vnode do not close.
81050Sstevel@tonic-gate  */
81060Sstevel@tonic-gate queue_t *
81070Sstevel@tonic-gate strvp2wq(vnode_t *vp)
81080Sstevel@tonic-gate {
81090Sstevel@tonic-gate 	ASSERT(vp->v_stream != NULL);
81100Sstevel@tonic-gate 	return (vp->v_stream->sd_wrq);
81110Sstevel@tonic-gate }
81120Sstevel@tonic-gate 
81130Sstevel@tonic-gate /*
81140Sstevel@tonic-gate  * pollwakeup stream head
81150Sstevel@tonic-gate  * It is the responsibility of the calling routine to ensure
81160Sstevel@tonic-gate  * that the stream or vnode do not close.
81170Sstevel@tonic-gate  */
81180Sstevel@tonic-gate void
81190Sstevel@tonic-gate strpollwakeup(vnode_t *vp, short event)
81200Sstevel@tonic-gate {
81210Sstevel@tonic-gate 	ASSERT(vp->v_stream);
81220Sstevel@tonic-gate 	pollwakeup(&vp->v_stream->sd_pollist, event);
81230Sstevel@tonic-gate }
81240Sstevel@tonic-gate 
81250Sstevel@tonic-gate /*
81260Sstevel@tonic-gate  * Mate the stream heads of two vnodes together. If the two vnodes are the
81270Sstevel@tonic-gate  * same, we just make the write-side point at the read-side -- otherwise,
81280Sstevel@tonic-gate  * we do a full mate.  Only works on vnodes associated with streams that are
81290Sstevel@tonic-gate  * still being built and thus have only a stream head.
81300Sstevel@tonic-gate  */
81310Sstevel@tonic-gate void
81320Sstevel@tonic-gate strmate(vnode_t *vp1, vnode_t *vp2)
81330Sstevel@tonic-gate {
81340Sstevel@tonic-gate 	queue_t *wrq1 = strvp2wq(vp1);
81350Sstevel@tonic-gate 	queue_t *wrq2 = strvp2wq(vp2);
81360Sstevel@tonic-gate 
81370Sstevel@tonic-gate 	/*
81380Sstevel@tonic-gate 	 * Verify that there are no modules on the stream yet.  We also
81390Sstevel@tonic-gate 	 * rely on the stream head always having a service procedure to
81400Sstevel@tonic-gate 	 * avoid tweaking q_nfsrv.
81410Sstevel@tonic-gate 	 */
81420Sstevel@tonic-gate 	ASSERT(wrq1->q_next == NULL && wrq2->q_next == NULL);
81430Sstevel@tonic-gate 	ASSERT(wrq1->q_qinfo->qi_srvp != NULL);
81440Sstevel@tonic-gate 	ASSERT(wrq2->q_qinfo->qi_srvp != NULL);
81450Sstevel@tonic-gate 
81460Sstevel@tonic-gate 	/*
81470Sstevel@tonic-gate 	 * If the queues are the same, just twist; otherwise do a full mate.
81480Sstevel@tonic-gate 	 */
81490Sstevel@tonic-gate 	if (wrq1 == wrq2) {
81500Sstevel@tonic-gate 		wrq1->q_next = _RD(wrq1);
81510Sstevel@tonic-gate 	} else {
81520Sstevel@tonic-gate 		wrq1->q_next = _RD(wrq2);
81530Sstevel@tonic-gate 		wrq2->q_next = _RD(wrq1);
81540Sstevel@tonic-gate 		STREAM(wrq1)->sd_mate = STREAM(wrq2);
81550Sstevel@tonic-gate 		STREAM(wrq1)->sd_flag |= STRMATE;
81560Sstevel@tonic-gate 		STREAM(wrq2)->sd_mate = STREAM(wrq1);
81570Sstevel@tonic-gate 		STREAM(wrq2)->sd_flag |= STRMATE;
81580Sstevel@tonic-gate 	}
81590Sstevel@tonic-gate }
81600Sstevel@tonic-gate 
81610Sstevel@tonic-gate /*
81620Sstevel@tonic-gate  * XXX will go away when console is correctly fixed.
81630Sstevel@tonic-gate  * Clean up the console PIDS, from previous I_SETSIG,
81640Sstevel@tonic-gate  * called only for cnopen which never calls strclean().
81650Sstevel@tonic-gate  */
81660Sstevel@tonic-gate void
81670Sstevel@tonic-gate str_cn_clean(struct vnode *vp)
81680Sstevel@tonic-gate {
81690Sstevel@tonic-gate 	strsig_t *ssp, *pssp, *tssp;
81700Sstevel@tonic-gate 	struct stdata *stp;
81710Sstevel@tonic-gate 	struct pid  *pidp;
81720Sstevel@tonic-gate 	int update = 0;
81730Sstevel@tonic-gate 
81740Sstevel@tonic-gate 	ASSERT(vp->v_stream);
81750Sstevel@tonic-gate 	stp = vp->v_stream;
81760Sstevel@tonic-gate 	pssp = NULL;
81770Sstevel@tonic-gate 	mutex_enter(&stp->sd_lock);
81780Sstevel@tonic-gate 	ssp = stp->sd_siglist;
81790Sstevel@tonic-gate 	while (ssp) {
81800Sstevel@tonic-gate 		mutex_enter(&pidlock);
81810Sstevel@tonic-gate 		pidp = ssp->ss_pidp;
81820Sstevel@tonic-gate 		/*
81830Sstevel@tonic-gate 		 * Get rid of PID if the proc is gone.
81840Sstevel@tonic-gate 		 */
81850Sstevel@tonic-gate 		if (pidp->pid_prinactive) {
81860Sstevel@tonic-gate 			tssp = ssp->ss_next;
81870Sstevel@tonic-gate 			if (pssp)
81880Sstevel@tonic-gate 				pssp->ss_next = tssp;
81890Sstevel@tonic-gate 			else
81900Sstevel@tonic-gate 				stp->sd_siglist = tssp;
81910Sstevel@tonic-gate 			ASSERT(pidp->pid_ref <= 1);
81920Sstevel@tonic-gate 			PID_RELE(ssp->ss_pidp);
81930Sstevel@tonic-gate 			mutex_exit(&pidlock);
81940Sstevel@tonic-gate 			kmem_free(ssp, sizeof (strsig_t));
81950Sstevel@tonic-gate 			update = 1;
81960Sstevel@tonic-gate 			ssp = tssp;
81970Sstevel@tonic-gate 			continue;
81980Sstevel@tonic-gate 		} else
81990Sstevel@tonic-gate 			mutex_exit(&pidlock);
82000Sstevel@tonic-gate 		pssp = ssp;
82010Sstevel@tonic-gate 		ssp = ssp->ss_next;
82020Sstevel@tonic-gate 	}
82030Sstevel@tonic-gate 	if (update) {
82040Sstevel@tonic-gate 		stp->sd_sigflags = 0;
82050Sstevel@tonic-gate 		for (ssp = stp->sd_siglist; ssp; ssp = ssp->ss_next)
82060Sstevel@tonic-gate 			stp->sd_sigflags |= ssp->ss_events;
82070Sstevel@tonic-gate 	}
82080Sstevel@tonic-gate 	mutex_exit(&stp->sd_lock);
82090Sstevel@tonic-gate }
82100Sstevel@tonic-gate 
82110Sstevel@tonic-gate /*
82120Sstevel@tonic-gate  * Return B_TRUE if there is data in the message, B_FALSE otherwise.
82130Sstevel@tonic-gate  */
82140Sstevel@tonic-gate static boolean_t
82150Sstevel@tonic-gate msghasdata(mblk_t *bp)
82160Sstevel@tonic-gate {
82170Sstevel@tonic-gate 	for (; bp; bp = bp->b_cont)
82180Sstevel@tonic-gate 		if (bp->b_datap->db_type == M_DATA) {
82190Sstevel@tonic-gate 			ASSERT(bp->b_wptr >= bp->b_rptr);
82200Sstevel@tonic-gate 			if (bp->b_wptr > bp->b_rptr)
82210Sstevel@tonic-gate 				return (B_TRUE);
82220Sstevel@tonic-gate 		}
82230Sstevel@tonic-gate 	return (B_FALSE);
82240Sstevel@tonic-gate }
8225