xref: /onnv-gate/usr/src/uts/common/os/streamio.c (revision 12617:d82a7bcb6fed)
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
51907Sedp  * Common Development and Distribution License (the "License").
61907Sedp  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
220Sstevel@tonic-gate /*	  All Rights Reserved  	*/
230Sstevel@tonic-gate 
240Sstevel@tonic-gate 
250Sstevel@tonic-gate /*
26*12602Sanil.udupa@sun.com  * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
270Sstevel@tonic-gate  */
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #include <sys/types.h>
300Sstevel@tonic-gate #include <sys/sysmacros.h>
310Sstevel@tonic-gate #include <sys/param.h>
320Sstevel@tonic-gate #include <sys/errno.h>
330Sstevel@tonic-gate #include <sys/signal.h>
340Sstevel@tonic-gate #include <sys/stat.h>
350Sstevel@tonic-gate #include <sys/proc.h>
360Sstevel@tonic-gate #include <sys/cred.h>
370Sstevel@tonic-gate #include <sys/user.h>
380Sstevel@tonic-gate #include <sys/vnode.h>
390Sstevel@tonic-gate #include <sys/file.h>
400Sstevel@tonic-gate #include <sys/stream.h>
410Sstevel@tonic-gate #include <sys/strsubr.h>
420Sstevel@tonic-gate #include <sys/stropts.h>
430Sstevel@tonic-gate #include <sys/tihdr.h>
440Sstevel@tonic-gate #include <sys/var.h>
450Sstevel@tonic-gate #include <sys/poll.h>
460Sstevel@tonic-gate #include <sys/termio.h>
470Sstevel@tonic-gate #include <sys/ttold.h>
480Sstevel@tonic-gate #include <sys/systm.h>
490Sstevel@tonic-gate #include <sys/uio.h>
500Sstevel@tonic-gate #include <sys/cmn_err.h>
510Sstevel@tonic-gate #include <sys/sad.h>
523448Sdh155122 #include <sys/netstack.h>
530Sstevel@tonic-gate #include <sys/priocntl.h>
540Sstevel@tonic-gate #include <sys/jioctl.h>
550Sstevel@tonic-gate #include <sys/procset.h>
560Sstevel@tonic-gate #include <sys/session.h>
570Sstevel@tonic-gate #include <sys/kmem.h>
580Sstevel@tonic-gate #include <sys/filio.h>
590Sstevel@tonic-gate #include <sys/vtrace.h>
600Sstevel@tonic-gate #include <sys/debug.h>
610Sstevel@tonic-gate #include <sys/strredir.h>
620Sstevel@tonic-gate #include <sys/fs/fifonode.h>
630Sstevel@tonic-gate #include <sys/fs/snode.h>
640Sstevel@tonic-gate #include <sys/strlog.h>
650Sstevel@tonic-gate #include <sys/strsun.h>
660Sstevel@tonic-gate #include <sys/project.h>
670Sstevel@tonic-gate #include <sys/kbio.h>
680Sstevel@tonic-gate #include <sys/msio.h>
690Sstevel@tonic-gate #include <sys/tty.h>
700Sstevel@tonic-gate #include <sys/ptyvar.h>
710Sstevel@tonic-gate #include <sys/vuid_event.h>
720Sstevel@tonic-gate #include <sys/modctl.h>
730Sstevel@tonic-gate #include <sys/sunddi.h>
740Sstevel@tonic-gate #include <sys/sunldi_impl.h>
750Sstevel@tonic-gate #include <sys/autoconf.h>
760Sstevel@tonic-gate #include <sys/policy.h>
775895Syz147064 #include <sys/dld.h>
783448Sdh155122 #include <sys/zone.h>
7911861SMarek.Pospisil@Sun.COM #include <c2/audit.h>
800Sstevel@tonic-gate 
812712Snn35248 /*
822712Snn35248  * This define helps improve the readability of streams code while
832712Snn35248  * still maintaining a very old streams performance enhancement.  The
842712Snn35248  * performance enhancement basically involved having all callers
852712Snn35248  * of straccess() perform the first check that straccess() will do
862712Snn35248  * locally before actually calling straccess().  (There by reducing
872712Snn35248  * the number of unnecessary calls to straccess().)
882712Snn35248  */
892712Snn35248 #define	i_straccess(x, y)	((stp->sd_sidp == NULL) ? 0 : \
902712Snn35248 				    (stp->sd_vnode->v_type == VFIFO) ? 0 : \
912712Snn35248 				    straccess((x), (y)))
922712Snn35248 
930Sstevel@tonic-gate /*
940Sstevel@tonic-gate  * what is mblk_pull_len?
950Sstevel@tonic-gate  *
960Sstevel@tonic-gate  * If a streams message consists of many short messages,
970Sstevel@tonic-gate  * a performance degradation occurs from copyout overhead.
980Sstevel@tonic-gate  * To decrease the per mblk overhead, messages that are
990Sstevel@tonic-gate  * likely to consist of many small mblks are pulled up into
1000Sstevel@tonic-gate  * one continuous chunk of memory.
1010Sstevel@tonic-gate  *
1020Sstevel@tonic-gate  * To avoid the processing overhead of examining every
1030Sstevel@tonic-gate  * mblk, a quick heuristic is used. If the first mblk in
1040Sstevel@tonic-gate  * the message is shorter than mblk_pull_len, it is likely
1050Sstevel@tonic-gate  * that the rest of the mblk will be short.
1060Sstevel@tonic-gate  *
1070Sstevel@tonic-gate  * This heuristic was decided upon after performance tests
1080Sstevel@tonic-gate  * indicated that anything more complex slowed down the main
1090Sstevel@tonic-gate  * code path.
1100Sstevel@tonic-gate  */
1110Sstevel@tonic-gate #define	MBLK_PULL_LEN 64
1120Sstevel@tonic-gate uint32_t mblk_pull_len = MBLK_PULL_LEN;
1130Sstevel@tonic-gate 
1140Sstevel@tonic-gate /*
1150Sstevel@tonic-gate  * The sgttyb_handling flag controls the handling of the old BSD
1160Sstevel@tonic-gate  * TIOCGETP, TIOCSETP, and TIOCSETN ioctls as follows:
1170Sstevel@tonic-gate  *
1180Sstevel@tonic-gate  * 0 - Emit no warnings at all and retain old, broken behavior.
1190Sstevel@tonic-gate  * 1 - Emit no warnings and silently handle new semantics.
1200Sstevel@tonic-gate  * 2 - Send cmn_err(CE_NOTE) when either TIOCSETP or TIOCSETN is used
1210Sstevel@tonic-gate  *     (once per system invocation).  Handle with new semantics.
1220Sstevel@tonic-gate  * 3 - Send SIGSYS when any TIOCGETP, TIOCSETP, or TIOCSETN call is
1230Sstevel@tonic-gate  *     made (so that offenders drop core and are easy to debug).
1240Sstevel@tonic-gate  *
1250Sstevel@tonic-gate  * The "new semantics" are that TIOCGETP returns B38400 for
1260Sstevel@tonic-gate  * sg_[io]speed if the corresponding value is over B38400, and that
1270Sstevel@tonic-gate  * TIOCSET[PN] accept B38400 in these cases to mean "retain current
1280Sstevel@tonic-gate  * bit rate."
1290Sstevel@tonic-gate  */
1300Sstevel@tonic-gate int sgttyb_handling = 1;
1310Sstevel@tonic-gate static boolean_t sgttyb_complaint;
1320Sstevel@tonic-gate 
1330Sstevel@tonic-gate /* don't push drcompat module by default on Style-2 streams */
1340Sstevel@tonic-gate static int push_drcompat = 0;
1350Sstevel@tonic-gate 
1360Sstevel@tonic-gate /*
1370Sstevel@tonic-gate  * id value used to distinguish between different ioctl messages
1380Sstevel@tonic-gate  */
1390Sstevel@tonic-gate static uint32_t ioc_id;
1400Sstevel@tonic-gate 
1410Sstevel@tonic-gate static void putback(struct stdata *, queue_t *, mblk_t *, int);
1420Sstevel@tonic-gate static void strcleanall(struct vnode *);
1430Sstevel@tonic-gate static int strwsrv(queue_t *);
1446583Smeem static int strdocmd(struct stdata *, struct strcmd *, cred_t *);
1450Sstevel@tonic-gate 
1460Sstevel@tonic-gate /*
1470Sstevel@tonic-gate  * qinit and module_info structures for stream head read and write queues
1480Sstevel@tonic-gate  */
1490Sstevel@tonic-gate struct module_info strm_info = { 0, "strrhead", 0, INFPSZ, STRHIGH, STRLOW };
1500Sstevel@tonic-gate struct module_info stwm_info = { 0, "strwhead", 0, 0, 0, 0 };
1510Sstevel@tonic-gate struct qinit strdata = { strrput, NULL, NULL, NULL, NULL, &strm_info };
1520Sstevel@tonic-gate struct qinit stwdata = { NULL, strwsrv, NULL, NULL, NULL, &stwm_info };
1530Sstevel@tonic-gate struct module_info fiform_info = { 0, "fifostrrhead", 0, PIPE_BUF, FIFOHIWAT,
1540Sstevel@tonic-gate     FIFOLOWAT };
1550Sstevel@tonic-gate struct module_info fifowm_info = { 0, "fifostrwhead", 0, 0, 0, 0 };
1560Sstevel@tonic-gate struct qinit fifo_strdata = { strrput, NULL, NULL, NULL, NULL, &fiform_info };
1570Sstevel@tonic-gate struct qinit fifo_stwdata = { NULL, strwsrv, NULL, NULL, NULL, &fifowm_info };
1580Sstevel@tonic-gate 
1590Sstevel@tonic-gate extern kmutex_t	strresources;	/* protects global resources */
1600Sstevel@tonic-gate extern kmutex_t muxifier;	/* single-threads multiplexor creation */
1610Sstevel@tonic-gate 
1620Sstevel@tonic-gate static boolean_t msghasdata(mblk_t *bp);
1630Sstevel@tonic-gate #define	msgnodata(bp) (!msghasdata(bp))
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate /*
1660Sstevel@tonic-gate  * Stream head locking notes:
1670Sstevel@tonic-gate  *	There are four monitors associated with the stream head:
1680Sstevel@tonic-gate  *	1. v_stream monitor: in stropen() and strclose() v_lock
1690Sstevel@tonic-gate  *		is held while the association of vnode and stream
1700Sstevel@tonic-gate  *		head is established or tested for.
1710Sstevel@tonic-gate  *	2. open/close/push/pop monitor: sd_lock is held while each
1720Sstevel@tonic-gate  *		thread bids for exclusive access to this monitor
1730Sstevel@tonic-gate  *		for opening or closing a stream.  In addition, this
1740Sstevel@tonic-gate  *		monitor is entered during pushes and pops.  This
1750Sstevel@tonic-gate  *		guarantees that during plumbing operations there
1760Sstevel@tonic-gate  *		is only one thread trying to change the plumbing.
1770Sstevel@tonic-gate  *		Any other threads present in the stream are only
1780Sstevel@tonic-gate  *		using the plumbing.
1790Sstevel@tonic-gate  *	3. read/write monitor: in the case of read, a thread holds
1800Sstevel@tonic-gate  *		sd_lock while trying to get data from the stream
1810Sstevel@tonic-gate  *		head queue.  if there is none to fulfill a read
1820Sstevel@tonic-gate  *		request, it sets RSLEEP and calls cv_wait_sig() down
1830Sstevel@tonic-gate  *		in strwaitq() to await the arrival of new data.
1840Sstevel@tonic-gate  *		when new data arrives in strrput(), sd_lock is acquired
1850Sstevel@tonic-gate  *		before testing for RSLEEP and calling cv_broadcast().
1860Sstevel@tonic-gate  *		the behavior of strwrite(), strwsrv(), and WSLEEP
1870Sstevel@tonic-gate  *		mirror this.
1880Sstevel@tonic-gate  *	4. ioctl monitor: sd_lock is gotten to ensure that only one
1890Sstevel@tonic-gate  *		thread is doing an ioctl at a time.
1900Sstevel@tonic-gate  */
1910Sstevel@tonic-gate 
1920Sstevel@tonic-gate static int
push_mod(queue_t * qp,dev_t * devp,struct stdata * stp,const char * name,int anchor,cred_t * crp,uint_t anchor_zoneid)1930Sstevel@tonic-gate push_mod(queue_t *qp, dev_t *devp, struct stdata *stp, const char *name,
1943448Sdh155122     int anchor, cred_t *crp, uint_t anchor_zoneid)
1950Sstevel@tonic-gate {
1960Sstevel@tonic-gate 	int error;
1970Sstevel@tonic-gate 	fmodsw_impl_t *fp;
1980Sstevel@tonic-gate 
1990Sstevel@tonic-gate 	if (stp->sd_flag & (STRHUP|STRDERR|STWRERR)) {
2000Sstevel@tonic-gate 		error = (stp->sd_flag & STRHUP) ? ENXIO : EIO;
2010Sstevel@tonic-gate 		return (error);
2020Sstevel@tonic-gate 	}
2030Sstevel@tonic-gate 	if (stp->sd_pushcnt >= nstrpush) {
2040Sstevel@tonic-gate 		return (EINVAL);
2050Sstevel@tonic-gate 	}
2060Sstevel@tonic-gate 
2070Sstevel@tonic-gate 	if ((fp = fmodsw_find(name, FMODSW_HOLD | FMODSW_LOAD)) == NULL) {
2080Sstevel@tonic-gate 		stp->sd_flag |= STREOPENFAIL;
2090Sstevel@tonic-gate 		return (EINVAL);
2100Sstevel@tonic-gate 	}
2110Sstevel@tonic-gate 
2120Sstevel@tonic-gate 	/*
2130Sstevel@tonic-gate 	 * push new module and call its open routine via qattach
2140Sstevel@tonic-gate 	 */
2150Sstevel@tonic-gate 	if ((error = qattach(qp, devp, 0, crp, fp, B_FALSE)) != 0)
2160Sstevel@tonic-gate 		return (error);
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate 	/*
2190Sstevel@tonic-gate 	 * Check to see if caller wants a STREAMS anchor
2200Sstevel@tonic-gate 	 * put at this place in the stream, and add if so.
2210Sstevel@tonic-gate 	 */
2220Sstevel@tonic-gate 	mutex_enter(&stp->sd_lock);
2233448Sdh155122 	if (anchor == stp->sd_pushcnt) {
2240Sstevel@tonic-gate 		stp->sd_anchor = stp->sd_pushcnt;
2253448Sdh155122 		stp->sd_anchorzone = anchor_zoneid;
2263448Sdh155122 	}
2270Sstevel@tonic-gate 	mutex_exit(&stp->sd_lock);
2280Sstevel@tonic-gate 
2290Sstevel@tonic-gate 	return (0);
2300Sstevel@tonic-gate }
2310Sstevel@tonic-gate 
2320Sstevel@tonic-gate /*
2330Sstevel@tonic-gate  * Open a stream device.
2340Sstevel@tonic-gate  */
2350Sstevel@tonic-gate int
stropen(vnode_t * vp,dev_t * devp,int flag,cred_t * crp)2360Sstevel@tonic-gate stropen(vnode_t *vp, dev_t *devp, int flag, cred_t *crp)
2370Sstevel@tonic-gate {
2380Sstevel@tonic-gate 	struct stdata *stp;
2390Sstevel@tonic-gate 	queue_t *qp;
2400Sstevel@tonic-gate 	int s;
2415895Syz147064 	dev_t dummydev, savedev;
2420Sstevel@tonic-gate 	struct autopush *ap;
2435895Syz147064 	struct dlautopush dlap;
2440Sstevel@tonic-gate 	int error = 0;
2450Sstevel@tonic-gate 	ssize_t	rmin, rmax;
2460Sstevel@tonic-gate 	int cloneopen;
2470Sstevel@tonic-gate 	queue_t *brq;
2480Sstevel@tonic-gate 	major_t major;
2493448Sdh155122 	str_stack_t *ss;
2503448Sdh155122 	zoneid_t zoneid;
2513448Sdh155122 	uint_t anchor;
2520Sstevel@tonic-gate 
2530Sstevel@tonic-gate 	/*
2540Sstevel@tonic-gate 	 * If the stream already exists, wait for any open in progress
2550Sstevel@tonic-gate 	 * to complete, then call the open function of each module and
2560Sstevel@tonic-gate 	 * driver in the stream.  Otherwise create the stream.
2570Sstevel@tonic-gate 	 */
2580Sstevel@tonic-gate 	TRACE_1(TR_FAC_STREAMS_FR, TR_STROPEN, "stropen:%p", vp);
2590Sstevel@tonic-gate retry:
2600Sstevel@tonic-gate 	mutex_enter(&vp->v_lock);
2610Sstevel@tonic-gate 	if ((stp = vp->v_stream) != NULL) {
2620Sstevel@tonic-gate 
2630Sstevel@tonic-gate 		/*
2640Sstevel@tonic-gate 		 * Waiting for stream to be created to device
2650Sstevel@tonic-gate 		 * due to another open.
2660Sstevel@tonic-gate 		 */
2675753Sgww 		mutex_exit(&vp->v_lock);
2685753Sgww 
2695753Sgww 		if (STRMATED(stp)) {
2705753Sgww 			struct stdata *strmatep = stp->sd_mate;
2715753Sgww 
2725753Sgww 			STRLOCKMATES(stp);
2735753Sgww 			if (strmatep->sd_flag & (STWOPEN|STRCLOSE|STRPLUMB)) {
2745753Sgww 				if (flag & (FNDELAY|FNONBLOCK)) {
2755753Sgww 					error = EAGAIN;
2765753Sgww 					mutex_exit(&strmatep->sd_lock);
2775753Sgww 					goto ckreturn;
2785753Sgww 				}
2795753Sgww 				mutex_exit(&stp->sd_lock);
2805753Sgww 				if (!cv_wait_sig(&strmatep->sd_monitor,
2815753Sgww 				    &strmatep->sd_lock)) {
2825753Sgww 					error = EINTR;
2835753Sgww 					mutex_exit(&strmatep->sd_lock);
2845753Sgww 					mutex_enter(&stp->sd_lock);
2855753Sgww 					goto ckreturn;
2865753Sgww 				}
2870Sstevel@tonic-gate 				mutex_exit(&strmatep->sd_lock);
2885753Sgww 				goto retry;
2895753Sgww 			}
2905753Sgww 			if (stp->sd_flag & (STWOPEN|STRCLOSE|STRPLUMB)) {
2915753Sgww 				if (flag & (FNDELAY|FNONBLOCK)) {
2925753Sgww 					error = EAGAIN;
2935753Sgww 					mutex_exit(&strmatep->sd_lock);
2945753Sgww 					goto ckreturn;
2955753Sgww 				}
2960Sstevel@tonic-gate 				mutex_exit(&strmatep->sd_lock);
2975753Sgww 				if (!cv_wait_sig(&stp->sd_monitor,
2985753Sgww 				    &stp->sd_lock)) {
2995753Sgww 					error = EINTR;
3005753Sgww 					goto ckreturn;
3015753Sgww 				}
3025753Sgww 				mutex_exit(&stp->sd_lock);
3035753Sgww 				goto retry;
3045753Sgww 			}
3055753Sgww 
3065753Sgww 			if (stp->sd_flag & (STRDERR|STWRERR)) {
3075753Sgww 				error = EIO;
3080Sstevel@tonic-gate 				mutex_exit(&strmatep->sd_lock);
3090Sstevel@tonic-gate 				goto ckreturn;
3100Sstevel@tonic-gate 			}
3115753Sgww 
3125753Sgww 			stp->sd_flag |= STWOPEN;
3135753Sgww 			STRUNLOCKMATES(stp);
3145753Sgww 		} else {
3155753Sgww 			mutex_enter(&stp->sd_lock);
3165753Sgww 			if (stp->sd_flag & (STWOPEN|STRCLOSE|STRPLUMB)) {
3175753Sgww 				if (flag & (FNDELAY|FNONBLOCK)) {
3185753Sgww 					error = EAGAIN;
3195753Sgww 					goto ckreturn;
3205753Sgww 				}
3215753Sgww 				if (!cv_wait_sig(&stp->sd_monitor,
3225753Sgww 				    &stp->sd_lock)) {
3235753Sgww 					error = EINTR;
3245753Sgww 					goto ckreturn;
3255753Sgww 				}
3265753Sgww 				mutex_exit(&stp->sd_lock);
3275753Sgww 				goto retry;  /* could be clone! */
3285753Sgww 			}
3295753Sgww 
3305753Sgww 			if (stp->sd_flag & (STRDERR|STWRERR)) {
3315753Sgww 				error = EIO;
3320Sstevel@tonic-gate 				goto ckreturn;
3330Sstevel@tonic-gate 			}
3345753Sgww 
3355753Sgww 			stp->sd_flag |= STWOPEN;
3360Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
3375753Sgww 		}
3380Sstevel@tonic-gate 
3390Sstevel@tonic-gate 		/*
3400Sstevel@tonic-gate 		 * Open all modules and devices down stream to notify
3410Sstevel@tonic-gate 		 * that another user is streaming.  For modules, set the
3420Sstevel@tonic-gate 		 * last argument to MODOPEN and do not pass any open flags.
3430Sstevel@tonic-gate 		 * Ignore dummydev since this is not the first open.
3440Sstevel@tonic-gate 		 */
3455753Sgww 		claimstr(stp->sd_wrq);
3465753Sgww 		qp = stp->sd_wrq;
3475753Sgww 		while (_SAMESTR(qp)) {
3485753Sgww 			qp = qp->q_next;
3495753Sgww 			if ((error = qreopen(_RD(qp), devp, flag, crp)) != 0)
3505753Sgww 				break;
3515753Sgww 		}
3525753Sgww 		releasestr(stp->sd_wrq);
3535753Sgww 		mutex_enter(&stp->sd_lock);
3545753Sgww 		stp->sd_flag &= ~(STRHUP|STWOPEN|STRDERR|STWRERR);
3555753Sgww 		stp->sd_rerror = 0;
3565753Sgww 		stp->sd_werror = 0;
3570Sstevel@tonic-gate ckreturn:
3585753Sgww 		cv_broadcast(&stp->sd_monitor);
3595753Sgww 		mutex_exit(&stp->sd_lock);
3605753Sgww 		return (error);
3610Sstevel@tonic-gate 	}
3620Sstevel@tonic-gate 
3630Sstevel@tonic-gate 	/*
3640Sstevel@tonic-gate 	 * This vnode isn't streaming.  SPECFS already
3650Sstevel@tonic-gate 	 * checked for multiple vnodes pointing to the
3660Sstevel@tonic-gate 	 * same stream, so create a stream to the driver.
3670Sstevel@tonic-gate 	 */
3680Sstevel@tonic-gate 	qp = allocq();
3690Sstevel@tonic-gate 	stp = shalloc(qp);
3700Sstevel@tonic-gate 
3710Sstevel@tonic-gate 	/*
3720Sstevel@tonic-gate 	 * Initialize stream head.  shalloc() has given us
3730Sstevel@tonic-gate 	 * exclusive access, and we have the vnode locked;
3740Sstevel@tonic-gate 	 * we can do whatever we want with stp.
3750Sstevel@tonic-gate 	 */
3760Sstevel@tonic-gate 	stp->sd_flag = STWOPEN;
3770Sstevel@tonic-gate 	stp->sd_siglist = NULL;
3780Sstevel@tonic-gate 	stp->sd_pollist.ph_list = NULL;
3790Sstevel@tonic-gate 	stp->sd_sigflags = 0;
3800Sstevel@tonic-gate 	stp->sd_mark = NULL;
3810Sstevel@tonic-gate 	stp->sd_closetime = STRTIMOUT;
3820Sstevel@tonic-gate 	stp->sd_sidp = NULL;
3830Sstevel@tonic-gate 	stp->sd_pgidp = NULL;
3840Sstevel@tonic-gate 	stp->sd_vnode = vp;
3850Sstevel@tonic-gate 	stp->sd_rerror = 0;
3860Sstevel@tonic-gate 	stp->sd_werror = 0;
3870Sstevel@tonic-gate 	stp->sd_wroff = 0;
388898Skais 	stp->sd_tail = 0;
3890Sstevel@tonic-gate 	stp->sd_iocblk = NULL;
3906583Smeem 	stp->sd_cmdblk = NULL;
3910Sstevel@tonic-gate 	stp->sd_pushcnt = 0;
3920Sstevel@tonic-gate 	stp->sd_qn_minpsz = 0;
3930Sstevel@tonic-gate 	stp->sd_qn_maxpsz = INFPSZ - 1;	/* used to check for initialization */
3940Sstevel@tonic-gate 	stp->sd_maxblk = INFPSZ;
3950Sstevel@tonic-gate 	qp->q_ptr = _WR(qp)->q_ptr = stp;
3960Sstevel@tonic-gate 	STREAM(qp) = STREAM(_WR(qp)) = stp;
3970Sstevel@tonic-gate 	vp->v_stream = stp;
3980Sstevel@tonic-gate 	mutex_exit(&vp->v_lock);
3990Sstevel@tonic-gate 	if (vp->v_type == VFIFO) {
4000Sstevel@tonic-gate 		stp->sd_flag |= OLDNDELAY;
4010Sstevel@tonic-gate 		/*
4020Sstevel@tonic-gate 		 * This means, both for pipes and fifos
4030Sstevel@tonic-gate 		 * strwrite will send SIGPIPE if the other
4040Sstevel@tonic-gate 		 * end is closed. For putmsg it depends
4050Sstevel@tonic-gate 		 * on whether it is a XPG4_2 application
4060Sstevel@tonic-gate 		 * or not
4070Sstevel@tonic-gate 		 */
4080Sstevel@tonic-gate 		stp->sd_wput_opt = SW_SIGPIPE;
4090Sstevel@tonic-gate 
4100Sstevel@tonic-gate 		/* setq might sleep in kmem_alloc - avoid holding locks. */
4110Sstevel@tonic-gate 		setq(qp, &fifo_strdata, &fifo_stwdata, NULL, QMTSAFE,
4120Sstevel@tonic-gate 		    SQ_CI|SQ_CO, B_FALSE);
4130Sstevel@tonic-gate 
4140Sstevel@tonic-gate 		set_qend(qp);
415560Smeem 		stp->sd_strtab = fifo_getinfo();
4160Sstevel@tonic-gate 		_WR(qp)->q_nfsrv = _WR(qp);
4170Sstevel@tonic-gate 		qp->q_nfsrv = qp;
4180Sstevel@tonic-gate 		/*
4190Sstevel@tonic-gate 		 * Wake up others that are waiting for stream to be created.
4200Sstevel@tonic-gate 		 */
4210Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
4220Sstevel@tonic-gate 		/*
4230Sstevel@tonic-gate 		 * nothing is be pushed on stream yet, so
4240Sstevel@tonic-gate 		 * optimized stream head packetsizes are just that
4250Sstevel@tonic-gate 		 * of the read queue
4260Sstevel@tonic-gate 		 */
4270Sstevel@tonic-gate 		stp->sd_qn_minpsz = qp->q_minpsz;
4280Sstevel@tonic-gate 		stp->sd_qn_maxpsz = qp->q_maxpsz;
4290Sstevel@tonic-gate 		stp->sd_flag &= ~STWOPEN;
4300Sstevel@tonic-gate 		goto fifo_opendone;
4310Sstevel@tonic-gate 	}
4320Sstevel@tonic-gate 	/* setq might sleep in kmem_alloc - avoid holding locks. */
4330Sstevel@tonic-gate 	setq(qp, &strdata, &stwdata, NULL, QMTSAFE, SQ_CI|SQ_CO, B_FALSE);
4340Sstevel@tonic-gate 
4350Sstevel@tonic-gate 	set_qend(qp);
4360Sstevel@tonic-gate 
4370Sstevel@tonic-gate 	/*
4380Sstevel@tonic-gate 	 * Open driver and create stream to it (via qattach).
4390Sstevel@tonic-gate 	 */
4405895Syz147064 	savedev = *devp;
4410Sstevel@tonic-gate 	cloneopen = (getmajor(*devp) == clone_major);
4420Sstevel@tonic-gate 	if ((error = qattach(qp, devp, flag, crp, NULL, B_FALSE)) != 0) {
4430Sstevel@tonic-gate 		mutex_enter(&vp->v_lock);
4440Sstevel@tonic-gate 		vp->v_stream = NULL;
4450Sstevel@tonic-gate 		mutex_exit(&vp->v_lock);
4460Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
4470Sstevel@tonic-gate 		cv_broadcast(&stp->sd_monitor);
4480Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
4490Sstevel@tonic-gate 		freeq(_RD(qp));
4500Sstevel@tonic-gate 		shfree(stp);
4510Sstevel@tonic-gate 		return (error);
4520Sstevel@tonic-gate 	}
4530Sstevel@tonic-gate 	/*
4540Sstevel@tonic-gate 	 * Set sd_strtab after open in order to handle clonable drivers
4550Sstevel@tonic-gate 	 */
4560Sstevel@tonic-gate 	stp->sd_strtab = STREAMSTAB(getmajor(*devp));
4570Sstevel@tonic-gate 
4580Sstevel@tonic-gate 	/*
4590Sstevel@tonic-gate 	 * Historical note: dummydev used to be be prior to the initial
4600Sstevel@tonic-gate 	 * open (via qattach above), which made the value seen
4610Sstevel@tonic-gate 	 * inconsistent between an I_PUSH and an autopush of a module.
4620Sstevel@tonic-gate 	 */
4630Sstevel@tonic-gate 	dummydev = *devp;
4640Sstevel@tonic-gate 
4650Sstevel@tonic-gate 	/*
4660Sstevel@tonic-gate 	 * For clone open of old style (Q not associated) network driver,
4670Sstevel@tonic-gate 	 * push DRMODNAME module to handle DL_ATTACH/DL_DETACH
4680Sstevel@tonic-gate 	 */
4690Sstevel@tonic-gate 	brq = _RD(_WR(qp)->q_next);
4700Sstevel@tonic-gate 	major = getmajor(*devp);
4710Sstevel@tonic-gate 	if (push_drcompat && cloneopen && NETWORK_DRV(major) &&
4720Sstevel@tonic-gate 	    ((brq->q_flag & _QASSOCIATED) == 0)) {
4733448Sdh155122 		if (push_mod(qp, &dummydev, stp, DRMODNAME, 0, crp, 0) != 0)
4740Sstevel@tonic-gate 			cmn_err(CE_WARN, "cannot push " DRMODNAME
4750Sstevel@tonic-gate 			    " streams module");
4760Sstevel@tonic-gate 	}
4770Sstevel@tonic-gate 
4785895Syz147064 	if (!NETWORK_DRV(major)) {
4795895Syz147064 		savedev = *devp;
4805895Syz147064 	} else {
4815895Syz147064 		/*
4825895Syz147064 		 * For network devices, process differently based on the
4835895Syz147064 		 * return value from dld_autopush():
4845895Syz147064 		 *
4855895Syz147064 		 *   0: the passed-in device points to a GLDv3 datalink with
4865895Syz147064 		 *   per-link autopush configuration; use that configuration
4875895Syz147064 		 *   and ignore any per-driver autopush configuration.
4885895Syz147064 		 *
4895895Syz147064 		 *   1: the passed-in device points to a physical GLDv3
4905895Syz147064 		 *   datalink without per-link autopush configuration.  The
4915895Syz147064 		 *   passed in device was changed to refer to the actual
4925895Syz147064 		 *   physical device (if it's not already); we use that new
4935895Syz147064 		 *   device to look up any per-driver autopush configuration.
4945895Syz147064 		 *
4955895Syz147064 		 *   -1: neither of the above cases applied; use the initial
4965895Syz147064 		 *   device to look up any per-driver autopush configuration.
4975895Syz147064 		 */
4985895Syz147064 		switch (dld_autopush(&savedev, &dlap)) {
4995895Syz147064 		case 0:
5005895Syz147064 			zoneid = crgetzoneid(crp);
5015895Syz147064 			for (s = 0; s < dlap.dap_npush; s++) {
5025895Syz147064 				error = push_mod(qp, &dummydev, stp,
5035895Syz147064 				    dlap.dap_aplist[s], dlap.dap_anchor, crp,
5045895Syz147064 				    zoneid);
5055895Syz147064 				if (error != 0)
5065895Syz147064 					break;
5075895Syz147064 			}
5085895Syz147064 			goto opendone;
5095895Syz147064 		case 1:
5105895Syz147064 			break;
5115895Syz147064 		case -1:
5125895Syz147064 			savedev = *devp;
5135895Syz147064 			break;
5145895Syz147064 		}
5155895Syz147064 	}
5160Sstevel@tonic-gate 	/*
5175895Syz147064 	 * Find the autopush configuration based on "savedev". Start with the
5185895Syz147064 	 * global zone. If not found check in the local zone.
5190Sstevel@tonic-gate 	 */
5203448Sdh155122 	zoneid = GLOBAL_ZONEID;
5213448Sdh155122 retryap:
5223448Sdh155122 	ss = netstack_find_by_stackid(zoneid_to_netstackid(zoneid))->
5233448Sdh155122 	    netstack_str;
5245895Syz147064 	if ((ap = sad_ap_find_by_dev(savedev, ss)) == NULL) {
5253448Sdh155122 		netstack_rele(ss->ss_netstack);
5263448Sdh155122 		if (zoneid == GLOBAL_ZONEID) {
5273448Sdh155122 			/*
5283448Sdh155122 			 * None found. Also look in the zone's autopush table.
5293448Sdh155122 			 */
5303448Sdh155122 			zoneid = crgetzoneid(crp);
5313448Sdh155122 			if (zoneid != GLOBAL_ZONEID)
5323448Sdh155122 				goto retryap;
5333448Sdh155122 		}
5340Sstevel@tonic-gate 		goto opendone;
5353448Sdh155122 	}
5363448Sdh155122 	anchor = ap->ap_anchor;
5373448Sdh155122 	zoneid = crgetzoneid(crp);
5380Sstevel@tonic-gate 	for (s = 0; s < ap->ap_npush; s++) {
5390Sstevel@tonic-gate 		error = push_mod(qp, &dummydev, stp, ap->ap_list[s],
5403448Sdh155122 		    anchor, crp, zoneid);
5410Sstevel@tonic-gate 		if (error != 0)
5420Sstevel@tonic-gate 			break;
5430Sstevel@tonic-gate 	}
5443448Sdh155122 	sad_ap_rele(ap, ss);
5453448Sdh155122 	netstack_rele(ss->ss_netstack);
5460Sstevel@tonic-gate 
5475895Syz147064 opendone:
5485895Syz147064 
5490Sstevel@tonic-gate 	/*
5500Sstevel@tonic-gate 	 * let specfs know that open failed part way through
5510Sstevel@tonic-gate 	 */
5520Sstevel@tonic-gate 	if (error) {
5530Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
5540Sstevel@tonic-gate 		stp->sd_flag |= STREOPENFAIL;
5550Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
5560Sstevel@tonic-gate 	}
5570Sstevel@tonic-gate 
5580Sstevel@tonic-gate 	/*
5590Sstevel@tonic-gate 	 * Wake up others that are waiting for stream to be created.
5600Sstevel@tonic-gate 	 */
5610Sstevel@tonic-gate 	mutex_enter(&stp->sd_lock);
5620Sstevel@tonic-gate 	stp->sd_flag &= ~STWOPEN;
5630Sstevel@tonic-gate 
5640Sstevel@tonic-gate 	/*
5650Sstevel@tonic-gate 	 * As a performance concern we are caching the values of
5660Sstevel@tonic-gate 	 * q_minpsz and q_maxpsz of the module below the stream
5670Sstevel@tonic-gate 	 * head in the stream head.
5680Sstevel@tonic-gate 	 */
5690Sstevel@tonic-gate 	mutex_enter(QLOCK(stp->sd_wrq->q_next));
5700Sstevel@tonic-gate 	rmin = stp->sd_wrq->q_next->q_minpsz;
5710Sstevel@tonic-gate 	rmax = stp->sd_wrq->q_next->q_maxpsz;
5720Sstevel@tonic-gate 	mutex_exit(QLOCK(stp->sd_wrq->q_next));
5730Sstevel@tonic-gate 
5740Sstevel@tonic-gate 	/* do this processing here as a performance concern */
5750Sstevel@tonic-gate 	if (strmsgsz != 0) {
5760Sstevel@tonic-gate 		if (rmax == INFPSZ)
5770Sstevel@tonic-gate 			rmax = strmsgsz;
5780Sstevel@tonic-gate 		else
5790Sstevel@tonic-gate 			rmax = MIN(strmsgsz, rmax);
5800Sstevel@tonic-gate 	}
5810Sstevel@tonic-gate 
5820Sstevel@tonic-gate 	mutex_enter(QLOCK(stp->sd_wrq));
5830Sstevel@tonic-gate 	stp->sd_qn_minpsz = rmin;
5840Sstevel@tonic-gate 	stp->sd_qn_maxpsz = rmax;
5850Sstevel@tonic-gate 	mutex_exit(QLOCK(stp->sd_wrq));
5860Sstevel@tonic-gate 
5870Sstevel@tonic-gate fifo_opendone:
5880Sstevel@tonic-gate 	cv_broadcast(&stp->sd_monitor);
5890Sstevel@tonic-gate 	mutex_exit(&stp->sd_lock);
5900Sstevel@tonic-gate 	return (error);
5910Sstevel@tonic-gate }
5920Sstevel@tonic-gate 
5930Sstevel@tonic-gate static int strsink(queue_t *, mblk_t *);
5940Sstevel@tonic-gate static struct qinit deadrend = {
5950Sstevel@tonic-gate 	strsink, NULL, NULL, NULL, NULL, &strm_info, NULL
5960Sstevel@tonic-gate };
5970Sstevel@tonic-gate static struct qinit deadwend = {
5980Sstevel@tonic-gate 	NULL, NULL, NULL, NULL, NULL, &stwm_info, NULL
5990Sstevel@tonic-gate };
6000Sstevel@tonic-gate 
6010Sstevel@tonic-gate /*
6020Sstevel@tonic-gate  * Close a stream.
6030Sstevel@tonic-gate  * This is called from closef() on the last close of an open stream.
6040Sstevel@tonic-gate  * Strclean() will already have removed the siglist and pollist
6050Sstevel@tonic-gate  * information, so all that remains is to remove all multiplexor links
6060Sstevel@tonic-gate  * for the stream, pop all the modules (and the driver), and free the
6070Sstevel@tonic-gate  * stream structure.
6080Sstevel@tonic-gate  */
6090Sstevel@tonic-gate 
6100Sstevel@tonic-gate int
strclose(struct vnode * vp,int flag,cred_t * crp)6110Sstevel@tonic-gate strclose(struct vnode *vp, int flag, cred_t *crp)
6120Sstevel@tonic-gate {
6130Sstevel@tonic-gate 	struct stdata *stp;
6140Sstevel@tonic-gate 	queue_t *qp;
6150Sstevel@tonic-gate 	int rval;
6160Sstevel@tonic-gate 	int freestp = 1;
6170Sstevel@tonic-gate 	queue_t *rmq;
6180Sstevel@tonic-gate 
6190Sstevel@tonic-gate 	TRACE_1(TR_FAC_STREAMS_FR,
6205753Sgww 	    TR_STRCLOSE, "strclose:%p", vp);
6210Sstevel@tonic-gate 	ASSERT(vp->v_stream);
6220Sstevel@tonic-gate 
6230Sstevel@tonic-gate 	stp = vp->v_stream;
6240Sstevel@tonic-gate 	ASSERT(!(stp->sd_flag & STPLEX));
6250Sstevel@tonic-gate 	qp = stp->sd_wrq;
6260Sstevel@tonic-gate 
6270Sstevel@tonic-gate 	/*
6280Sstevel@tonic-gate 	 * Needed so that strpoll will return non-zero for this fd.
6290Sstevel@tonic-gate 	 * Note that with POLLNOERR STRHUP does still cause POLLHUP.
6300Sstevel@tonic-gate 	 */
6310Sstevel@tonic-gate 	mutex_enter(&stp->sd_lock);
6320Sstevel@tonic-gate 	stp->sd_flag |= STRHUP;
6330Sstevel@tonic-gate 	mutex_exit(&stp->sd_lock);
6340Sstevel@tonic-gate 
6350Sstevel@tonic-gate 	/*
6360Sstevel@tonic-gate 	 * If the registered process or process group did not have an
6370Sstevel@tonic-gate 	 * open instance of this stream then strclean would not be
6380Sstevel@tonic-gate 	 * called. Thus at the time of closing all remaining siglist entries
6390Sstevel@tonic-gate 	 * are removed.
6400Sstevel@tonic-gate 	 */
6410Sstevel@tonic-gate 	if (stp->sd_siglist != NULL)
6420Sstevel@tonic-gate 		strcleanall(vp);
6430Sstevel@tonic-gate 
6440Sstevel@tonic-gate 	ASSERT(stp->sd_siglist == NULL);
6450Sstevel@tonic-gate 	ASSERT(stp->sd_sigflags == 0);
6460Sstevel@tonic-gate 
6470Sstevel@tonic-gate 	if (STRMATED(stp)) {
6480Sstevel@tonic-gate 		struct stdata *strmatep = stp->sd_mate;
6490Sstevel@tonic-gate 		int waited = 1;
6500Sstevel@tonic-gate 
6510Sstevel@tonic-gate 		STRLOCKMATES(stp);
6520Sstevel@tonic-gate 		while (waited) {
6530Sstevel@tonic-gate 			waited = 0;
6540Sstevel@tonic-gate 			while (stp->sd_flag & (STWOPEN|STRCLOSE|STRPLUMB)) {
6550Sstevel@tonic-gate 				mutex_exit(&strmatep->sd_lock);
6560Sstevel@tonic-gate 				cv_wait(&stp->sd_monitor, &stp->sd_lock);
6570Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
6580Sstevel@tonic-gate 				STRLOCKMATES(stp);
6590Sstevel@tonic-gate 				waited = 1;
6600Sstevel@tonic-gate 			}
6610Sstevel@tonic-gate 			while (strmatep->sd_flag &
6620Sstevel@tonic-gate 			    (STWOPEN|STRCLOSE|STRPLUMB)) {
6630Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
6640Sstevel@tonic-gate 				cv_wait(&strmatep->sd_monitor,
6650Sstevel@tonic-gate 				    &strmatep->sd_lock);
6660Sstevel@tonic-gate 				mutex_exit(&strmatep->sd_lock);
6670Sstevel@tonic-gate 				STRLOCKMATES(stp);
6680Sstevel@tonic-gate 				waited = 1;
6690Sstevel@tonic-gate 			}
6700Sstevel@tonic-gate 		}
6710Sstevel@tonic-gate 		stp->sd_flag |= STRCLOSE;
6720Sstevel@tonic-gate 		STRUNLOCKMATES(stp);
6730Sstevel@tonic-gate 	} else {
6740Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
6750Sstevel@tonic-gate 		stp->sd_flag |= STRCLOSE;
6760Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
6770Sstevel@tonic-gate 	}
6780Sstevel@tonic-gate 
6790Sstevel@tonic-gate 	ASSERT(qp->q_first == NULL);	/* No more delayed write */
6800Sstevel@tonic-gate 
6810Sstevel@tonic-gate 	/* Check if an I_LINK was ever done on this stream */
6820Sstevel@tonic-gate 	if (stp->sd_flag & STRHASLINKS) {
6833448Sdh155122 		netstack_t *ns;
6843448Sdh155122 		str_stack_t *ss;
6853448Sdh155122 
6863448Sdh155122 		ns = netstack_find_by_cred(crp);
6873448Sdh155122 		ASSERT(ns != NULL);
6883448Sdh155122 		ss = ns->netstack_str;
6893448Sdh155122 		ASSERT(ss != NULL);
6903448Sdh155122 
6913448Sdh155122 		(void) munlinkall(stp, LINKCLOSE|LINKNORMAL, crp, &rval, ss);
6923448Sdh155122 		netstack_rele(ss->ss_netstack);
6930Sstevel@tonic-gate 	}
6940Sstevel@tonic-gate 
6950Sstevel@tonic-gate 	while (_SAMESTR(qp)) {
6960Sstevel@tonic-gate 		/*
6970Sstevel@tonic-gate 		 * Holding sd_lock prevents q_next from changing in
6980Sstevel@tonic-gate 		 * this stream.
6990Sstevel@tonic-gate 		 */
7000Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
7010Sstevel@tonic-gate 		if (!(flag & (FNDELAY|FNONBLOCK)) && (stp->sd_closetime > 0)) {
7020Sstevel@tonic-gate 
7030Sstevel@tonic-gate 			/*
7040Sstevel@tonic-gate 			 * sleep until awakened by strwsrv() or timeout
7050Sstevel@tonic-gate 			 */
7060Sstevel@tonic-gate 			for (;;) {
7070Sstevel@tonic-gate 				mutex_enter(QLOCK(qp->q_next));
7080Sstevel@tonic-gate 				if (!(qp->q_next->q_mblkcnt)) {
7090Sstevel@tonic-gate 					mutex_exit(QLOCK(qp->q_next));
7100Sstevel@tonic-gate 					break;
7110Sstevel@tonic-gate 				}
7120Sstevel@tonic-gate 				stp->sd_flag |= WSLEEP;
7130Sstevel@tonic-gate 
7140Sstevel@tonic-gate 				/* ensure strwsrv gets enabled */
7150Sstevel@tonic-gate 				qp->q_next->q_flag |= QWANTW;
7160Sstevel@tonic-gate 				mutex_exit(QLOCK(qp->q_next));
7170Sstevel@tonic-gate 				/* get out if we timed out or recv'd a signal */
7180Sstevel@tonic-gate 				if (str_cv_wait(&qp->q_wait, &stp->sd_lock,
7190Sstevel@tonic-gate 				    stp->sd_closetime, 0) <= 0) {
7200Sstevel@tonic-gate 					break;
7210Sstevel@tonic-gate 				}
7220Sstevel@tonic-gate 			}
7230Sstevel@tonic-gate 			stp->sd_flag &= ~WSLEEP;
7240Sstevel@tonic-gate 		}
7250Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
7260Sstevel@tonic-gate 
7270Sstevel@tonic-gate 		rmq = qp->q_next;
7280Sstevel@tonic-gate 		if (rmq->q_flag & QISDRV) {
7290Sstevel@tonic-gate 			ASSERT(!_SAMESTR(rmq));
7300Sstevel@tonic-gate 			wait_sq_svc(_RD(qp)->q_syncq);
7310Sstevel@tonic-gate 		}
7320Sstevel@tonic-gate 
7330Sstevel@tonic-gate 		qdetach(_RD(rmq), 1, flag, crp, B_FALSE);
7340Sstevel@tonic-gate 	}
7350Sstevel@tonic-gate 
7361907Sedp 	/*
7371907Sedp 	 * Since we call pollwakeup in close() now, the poll list should
7381907Sedp 	 * be empty in most cases. The only exception is the layered devices
7391907Sedp 	 * (e.g. the console drivers with redirection modules pushed on top
7401907Sedp 	 * of it).  We have to do this after calling qdetach() because
7411907Sedp 	 * the redirection module won't have torn down the console
7421907Sedp 	 * redirection until after qdetach() has been invoked.
7431907Sedp 	 */
7441907Sedp 	if (stp->sd_pollist.ph_list != NULL) {
7451907Sedp 		pollwakeup(&stp->sd_pollist, POLLERR);
7461907Sedp 		pollhead_clean(&stp->sd_pollist);
7471907Sedp 	}
7481907Sedp 	ASSERT(stp->sd_pollist.ph_list == NULL);
7491907Sedp 	ASSERT(stp->sd_sidp == NULL);
7501907Sedp 	ASSERT(stp->sd_pgidp == NULL);
7511907Sedp 
7520Sstevel@tonic-gate 	/* Prevent qenable from re-enabling the stream head queue */
7530Sstevel@tonic-gate 	disable_svc(_RD(qp));
7540Sstevel@tonic-gate 
7550Sstevel@tonic-gate 	/*
7560Sstevel@tonic-gate 	 * Wait until service procedure of each queue is
7570Sstevel@tonic-gate 	 * run, if QINSERVICE is set.
7580Sstevel@tonic-gate 	 */
7590Sstevel@tonic-gate 	wait_svc(_RD(qp));
7600Sstevel@tonic-gate 
7610Sstevel@tonic-gate 	/*
7620Sstevel@tonic-gate 	 * Now, flush both queues.
7630Sstevel@tonic-gate 	 */
7640Sstevel@tonic-gate 	flushq(_RD(qp), FLUSHALL);
7650Sstevel@tonic-gate 	flushq(qp, FLUSHALL);
7660Sstevel@tonic-gate 
7670Sstevel@tonic-gate 	/*
7680Sstevel@tonic-gate 	 * If the write queue of the stream head is pointing to a
7690Sstevel@tonic-gate 	 * read queue, we have a twisted stream.  If the read queue
7700Sstevel@tonic-gate 	 * is alive, convert the stream head queues into a dead end.
7710Sstevel@tonic-gate 	 * If the read queue is dead, free the dead pair.
7720Sstevel@tonic-gate 	 */
7730Sstevel@tonic-gate 	if (qp->q_next && !_SAMESTR(qp)) {
7740Sstevel@tonic-gate 		if (qp->q_next->q_qinfo == &deadrend) {	/* half-closed pipe */
7750Sstevel@tonic-gate 			flushq(qp->q_next, FLUSHALL); /* ensure no message */
7760Sstevel@tonic-gate 			shfree(qp->q_next->q_stream);
7770Sstevel@tonic-gate 			freeq(qp->q_next);
7780Sstevel@tonic-gate 			freeq(_RD(qp));
7790Sstevel@tonic-gate 		} else if (qp->q_next == _RD(qp)) {	/* fifo */
7800Sstevel@tonic-gate 			freeq(_RD(qp));
7810Sstevel@tonic-gate 		} else {				/* pipe */
7820Sstevel@tonic-gate 			freestp = 0;
7830Sstevel@tonic-gate 			/*
7840Sstevel@tonic-gate 			 * The q_info pointers are never accessed when
7850Sstevel@tonic-gate 			 * SQLOCK is held.
7860Sstevel@tonic-gate 			 */
7870Sstevel@tonic-gate 			ASSERT(qp->q_syncq == _RD(qp)->q_syncq);
7880Sstevel@tonic-gate 			mutex_enter(SQLOCK(qp->q_syncq));
7890Sstevel@tonic-gate 			qp->q_qinfo = &deadwend;
7900Sstevel@tonic-gate 			_RD(qp)->q_qinfo = &deadrend;
7910Sstevel@tonic-gate 			mutex_exit(SQLOCK(qp->q_syncq));
7920Sstevel@tonic-gate 		}
7930Sstevel@tonic-gate 	} else {
7940Sstevel@tonic-gate 		freeq(_RD(qp)); /* free stream head queue pair */
7950Sstevel@tonic-gate 	}
7960Sstevel@tonic-gate 
7970Sstevel@tonic-gate 	mutex_enter(&vp->v_lock);
7980Sstevel@tonic-gate 	if (stp->sd_iocblk) {
7990Sstevel@tonic-gate 		if (stp->sd_iocblk != (mblk_t *)-1) {
8000Sstevel@tonic-gate 			freemsg(stp->sd_iocblk);
8010Sstevel@tonic-gate 		}
8020Sstevel@tonic-gate 		stp->sd_iocblk = NULL;
8030Sstevel@tonic-gate 	}
8040Sstevel@tonic-gate 	stp->sd_vnode = NULL;
8050Sstevel@tonic-gate 	vp->v_stream = NULL;
8060Sstevel@tonic-gate 	mutex_exit(&vp->v_lock);
8070Sstevel@tonic-gate 	mutex_enter(&stp->sd_lock);
8086583Smeem 	freemsg(stp->sd_cmdblk);
8096583Smeem 	stp->sd_cmdblk = NULL;
8100Sstevel@tonic-gate 	stp->sd_flag &= ~STRCLOSE;
8110Sstevel@tonic-gate 	cv_broadcast(&stp->sd_monitor);
8120Sstevel@tonic-gate 	mutex_exit(&stp->sd_lock);
8130Sstevel@tonic-gate 
8140Sstevel@tonic-gate 	if (freestp)
8150Sstevel@tonic-gate 		shfree(stp);
8160Sstevel@tonic-gate 	return (0);
8170Sstevel@tonic-gate }
8180Sstevel@tonic-gate 
8190Sstevel@tonic-gate static int
strsink(queue_t * q,mblk_t * bp)8200Sstevel@tonic-gate strsink(queue_t *q, mblk_t *bp)
8210Sstevel@tonic-gate {
8220Sstevel@tonic-gate 	struct copyresp *resp;
8230Sstevel@tonic-gate 
8240Sstevel@tonic-gate 	switch (bp->b_datap->db_type) {
8250Sstevel@tonic-gate 	case M_FLUSH:
8260Sstevel@tonic-gate 		if ((*bp->b_rptr & FLUSHW) && !(bp->b_flag & MSGNOLOOP)) {
8270Sstevel@tonic-gate 			*bp->b_rptr &= ~FLUSHR;
8280Sstevel@tonic-gate 			bp->b_flag |= MSGNOLOOP;
8290Sstevel@tonic-gate 			/*
8300Sstevel@tonic-gate 			 * Protect against the driver passing up
8310Sstevel@tonic-gate 			 * messages after it has done a qprocsoff.
8320Sstevel@tonic-gate 			 */
8330Sstevel@tonic-gate 			if (_OTHERQ(q)->q_next == NULL)
8340Sstevel@tonic-gate 				freemsg(bp);
8350Sstevel@tonic-gate 			else
8360Sstevel@tonic-gate 				qreply(q, bp);
8370Sstevel@tonic-gate 		} else {
8380Sstevel@tonic-gate 			freemsg(bp);
8390Sstevel@tonic-gate 		}
8400Sstevel@tonic-gate 		break;
8410Sstevel@tonic-gate 
8420Sstevel@tonic-gate 	case M_COPYIN:
8430Sstevel@tonic-gate 	case M_COPYOUT:
8440Sstevel@tonic-gate 		if (bp->b_cont) {
8450Sstevel@tonic-gate 			freemsg(bp->b_cont);
8460Sstevel@tonic-gate 			bp->b_cont = NULL;
8470Sstevel@tonic-gate 		}
8480Sstevel@tonic-gate 		bp->b_datap->db_type = M_IOCDATA;
8490Sstevel@tonic-gate 		bp->b_wptr = bp->b_rptr + sizeof (struct copyresp);
8500Sstevel@tonic-gate 		resp = (struct copyresp *)bp->b_rptr;
8510Sstevel@tonic-gate 		resp->cp_rval = (caddr_t)1;	/* failure */
8520Sstevel@tonic-gate 		/*
8530Sstevel@tonic-gate 		 * Protect against the driver passing up
8540Sstevel@tonic-gate 		 * messages after it has done a qprocsoff.
8550Sstevel@tonic-gate 		 */
8560Sstevel@tonic-gate 		if (_OTHERQ(q)->q_next == NULL)
8570Sstevel@tonic-gate 			freemsg(bp);
8580Sstevel@tonic-gate 		else
8590Sstevel@tonic-gate 			qreply(q, bp);
8600Sstevel@tonic-gate 		break;
8610Sstevel@tonic-gate 
8620Sstevel@tonic-gate 	case M_IOCTL:
8630Sstevel@tonic-gate 		if (bp->b_cont) {
8640Sstevel@tonic-gate 			freemsg(bp->b_cont);
8650Sstevel@tonic-gate 			bp->b_cont = NULL;
8660Sstevel@tonic-gate 		}
8670Sstevel@tonic-gate 		bp->b_datap->db_type = M_IOCNAK;
8680Sstevel@tonic-gate 		/*
8690Sstevel@tonic-gate 		 * Protect against the driver passing up
8700Sstevel@tonic-gate 		 * messages after it has done a qprocsoff.
8710Sstevel@tonic-gate 		 */
8720Sstevel@tonic-gate 		if (_OTHERQ(q)->q_next == NULL)
8730Sstevel@tonic-gate 			freemsg(bp);
8740Sstevel@tonic-gate 		else
8750Sstevel@tonic-gate 			qreply(q, bp);
8760Sstevel@tonic-gate 		break;
8770Sstevel@tonic-gate 
8780Sstevel@tonic-gate 	default:
8790Sstevel@tonic-gate 		freemsg(bp);
8800Sstevel@tonic-gate 		break;
8810Sstevel@tonic-gate 	}
8820Sstevel@tonic-gate 
8830Sstevel@tonic-gate 	return (0);
8840Sstevel@tonic-gate }
8850Sstevel@tonic-gate 
8860Sstevel@tonic-gate /*
8870Sstevel@tonic-gate  * Clean up after a process when it closes a stream.  This is called
8880Sstevel@tonic-gate  * from closef for all closes, whereas strclose is called only for the
8890Sstevel@tonic-gate  * last close on a stream.  The siglist is scanned for entries for the
8900Sstevel@tonic-gate  * current process, and these are removed.
8910Sstevel@tonic-gate  */
8920Sstevel@tonic-gate void
strclean(struct vnode * vp)8930Sstevel@tonic-gate strclean(struct vnode *vp)
8940Sstevel@tonic-gate {
8950Sstevel@tonic-gate 	strsig_t *ssp, *pssp, *tssp;
8960Sstevel@tonic-gate 	stdata_t *stp;
8970Sstevel@tonic-gate 	int update = 0;
8980Sstevel@tonic-gate 
8990Sstevel@tonic-gate 	TRACE_1(TR_FAC_STREAMS_FR,
9005753Sgww 	    TR_STRCLEAN, "strclean:%p", vp);
9010Sstevel@tonic-gate 	stp = vp->v_stream;
9020Sstevel@tonic-gate 	pssp = NULL;
9030Sstevel@tonic-gate 	mutex_enter(&stp->sd_lock);
9040Sstevel@tonic-gate 	ssp = stp->sd_siglist;
9050Sstevel@tonic-gate 	while (ssp) {
9060Sstevel@tonic-gate 		if (ssp->ss_pidp == curproc->p_pidp) {
9070Sstevel@tonic-gate 			tssp = ssp->ss_next;
9080Sstevel@tonic-gate 			if (pssp)
9090Sstevel@tonic-gate 				pssp->ss_next = tssp;
9100Sstevel@tonic-gate 			else
9110Sstevel@tonic-gate 				stp->sd_siglist = tssp;
9120Sstevel@tonic-gate 			mutex_enter(&pidlock);
9130Sstevel@tonic-gate 			PID_RELE(ssp->ss_pidp);
9140Sstevel@tonic-gate 			mutex_exit(&pidlock);
9150Sstevel@tonic-gate 			kmem_free(ssp, sizeof (strsig_t));
9160Sstevel@tonic-gate 			update = 1;
9170Sstevel@tonic-gate 			ssp = tssp;
9180Sstevel@tonic-gate 		} else {
9190Sstevel@tonic-gate 			pssp = ssp;
9200Sstevel@tonic-gate 			ssp = ssp->ss_next;
9210Sstevel@tonic-gate 		}
9220Sstevel@tonic-gate 	}
9230Sstevel@tonic-gate 	if (update) {
9240Sstevel@tonic-gate 		stp->sd_sigflags = 0;
9250Sstevel@tonic-gate 		for (ssp = stp->sd_siglist; ssp; ssp = ssp->ss_next)
9260Sstevel@tonic-gate 			stp->sd_sigflags |= ssp->ss_events;
9270Sstevel@tonic-gate 	}
9280Sstevel@tonic-gate 	mutex_exit(&stp->sd_lock);
9290Sstevel@tonic-gate }
9300Sstevel@tonic-gate 
9310Sstevel@tonic-gate /*
9320Sstevel@tonic-gate  * Used on the last close to remove any remaining items on the siglist.
9330Sstevel@tonic-gate  * These could be present on the siglist due to I_ESETSIG calls that
9340Sstevel@tonic-gate  * use process groups or processed that do not have an open file descriptor
9350Sstevel@tonic-gate  * for this stream (Such entries would not be removed by strclean).
9360Sstevel@tonic-gate  */
9370Sstevel@tonic-gate static void
strcleanall(struct vnode * vp)9380Sstevel@tonic-gate strcleanall(struct vnode *vp)
9390Sstevel@tonic-gate {
9400Sstevel@tonic-gate 	strsig_t *ssp, *nssp;
9410Sstevel@tonic-gate 	stdata_t *stp;
9420Sstevel@tonic-gate 
9430Sstevel@tonic-gate 	stp = vp->v_stream;
9440Sstevel@tonic-gate 	mutex_enter(&stp->sd_lock);
9450Sstevel@tonic-gate 	ssp = stp->sd_siglist;
9460Sstevel@tonic-gate 	stp->sd_siglist = NULL;
9470Sstevel@tonic-gate 	while (ssp) {
9480Sstevel@tonic-gate 		nssp = ssp->ss_next;
9490Sstevel@tonic-gate 		mutex_enter(&pidlock);
9500Sstevel@tonic-gate 		PID_RELE(ssp->ss_pidp);
9510Sstevel@tonic-gate 		mutex_exit(&pidlock);
9520Sstevel@tonic-gate 		kmem_free(ssp, sizeof (strsig_t));
9530Sstevel@tonic-gate 		ssp = nssp;
9540Sstevel@tonic-gate 	}
9550Sstevel@tonic-gate 	stp->sd_sigflags = 0;
9560Sstevel@tonic-gate 	mutex_exit(&stp->sd_lock);
9570Sstevel@tonic-gate }
9580Sstevel@tonic-gate 
9590Sstevel@tonic-gate /*
9600Sstevel@tonic-gate  * Retrieve the next message from the logical stream head read queue
9610Sstevel@tonic-gate  * using either rwnext (if sync stream) or getq_noenab.
9620Sstevel@tonic-gate  * It is the callers responsibility to call qbackenable after
9630Sstevel@tonic-gate  * it is finished with the message. The caller should not call
9640Sstevel@tonic-gate  * qbackenable until after any putback calls to avoid spurious backenabling.
9650Sstevel@tonic-gate  */
9660Sstevel@tonic-gate mblk_t *
strget(struct stdata * stp,queue_t * q,struct uio * uiop,int first,int * errorp)9670Sstevel@tonic-gate strget(struct stdata *stp, queue_t *q, struct uio *uiop, int first,
9680Sstevel@tonic-gate     int *errorp)
9690Sstevel@tonic-gate {
9700Sstevel@tonic-gate 	mblk_t *bp;
9710Sstevel@tonic-gate 	int error;
9726769Sja97890 	ssize_t rbytes = 0;
9736769Sja97890 
9746769Sja97890 	/* Holding sd_lock prevents the read queue from changing  */
9750Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&stp->sd_lock));
9760Sstevel@tonic-gate 
9770Sstevel@tonic-gate 	if (uiop != NULL && stp->sd_struiordq != NULL &&
9780Sstevel@tonic-gate 	    q->q_first == NULL &&
9790Sstevel@tonic-gate 	    (!first || (stp->sd_wakeq & RSLEEP))) {
9800Sstevel@tonic-gate 		/*
9810Sstevel@tonic-gate 		 * Stream supports rwnext() for the read side.
9820Sstevel@tonic-gate 		 * If this is the first time we're called by e.g. strread
9830Sstevel@tonic-gate 		 * only do the downcall if there is a deferred wakeup
9840Sstevel@tonic-gate 		 * (registered in sd_wakeq).
9850Sstevel@tonic-gate 		 */
9860Sstevel@tonic-gate 		struiod_t uiod;
9870Sstevel@tonic-gate 
9880Sstevel@tonic-gate 		if (first)
9890Sstevel@tonic-gate 			stp->sd_wakeq &= ~RSLEEP;
9900Sstevel@tonic-gate 
9910Sstevel@tonic-gate 		(void) uiodup(uiop, &uiod.d_uio, uiod.d_iov,
9925753Sgww 		    sizeof (uiod.d_iov) / sizeof (*uiod.d_iov));
9930Sstevel@tonic-gate 		uiod.d_mp = 0;
9940Sstevel@tonic-gate 		/*
9950Sstevel@tonic-gate 		 * Mark that a thread is in rwnext on the read side
9960Sstevel@tonic-gate 		 * to prevent strrput from nacking ioctls immediately.
9970Sstevel@tonic-gate 		 * When the last concurrent rwnext returns
9980Sstevel@tonic-gate 		 * the ioctls are nack'ed.
9990Sstevel@tonic-gate 		 */
10000Sstevel@tonic-gate 		ASSERT(MUTEX_HELD(&stp->sd_lock));
10010Sstevel@tonic-gate 		stp->sd_struiodnak++;
10020Sstevel@tonic-gate 		/*
10030Sstevel@tonic-gate 		 * Note: rwnext will drop sd_lock.
10040Sstevel@tonic-gate 		 */
10050Sstevel@tonic-gate 		error = rwnext(q, &uiod);
10060Sstevel@tonic-gate 		ASSERT(MUTEX_NOT_HELD(&stp->sd_lock));
10070Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
10080Sstevel@tonic-gate 		stp->sd_struiodnak--;
10090Sstevel@tonic-gate 		while (stp->sd_struiodnak == 0 &&
10100Sstevel@tonic-gate 		    ((bp = stp->sd_struionak) != NULL)) {
10110Sstevel@tonic-gate 			stp->sd_struionak = bp->b_next;
10120Sstevel@tonic-gate 			bp->b_next = NULL;
10130Sstevel@tonic-gate 			bp->b_datap->db_type = M_IOCNAK;
10140Sstevel@tonic-gate 			/*
10150Sstevel@tonic-gate 			 * Protect against the driver passing up
10160Sstevel@tonic-gate 			 * messages after it has done a qprocsoff.
10170Sstevel@tonic-gate 			 */
10180Sstevel@tonic-gate 			if (_OTHERQ(q)->q_next == NULL)
10190Sstevel@tonic-gate 				freemsg(bp);
10200Sstevel@tonic-gate 			else {
10210Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
10220Sstevel@tonic-gate 				qreply(q, bp);
10230Sstevel@tonic-gate 				mutex_enter(&stp->sd_lock);
10240Sstevel@tonic-gate 			}
10250Sstevel@tonic-gate 		}
10260Sstevel@tonic-gate 		ASSERT(MUTEX_HELD(&stp->sd_lock));
10270Sstevel@tonic-gate 		if (error == 0 || error == EWOULDBLOCK) {
10280Sstevel@tonic-gate 			if ((bp = uiod.d_mp) != NULL) {
10290Sstevel@tonic-gate 				*errorp = 0;
10300Sstevel@tonic-gate 				ASSERT(MUTEX_HELD(&stp->sd_lock));
10310Sstevel@tonic-gate 				return (bp);
10320Sstevel@tonic-gate 			}
10330Sstevel@tonic-gate 			error = 0;
10340Sstevel@tonic-gate 		} else if (error == EINVAL) {
10350Sstevel@tonic-gate 			/*
10360Sstevel@tonic-gate 			 * The stream plumbing must have
10370Sstevel@tonic-gate 			 * changed while we were away, so
10380Sstevel@tonic-gate 			 * just turn off rwnext()s.
10390Sstevel@tonic-gate 			 */
10400Sstevel@tonic-gate 			error = 0;
10410Sstevel@tonic-gate 		} else if (error == EBUSY) {
10420Sstevel@tonic-gate 			/*
10430Sstevel@tonic-gate 			 * The module might have data in transit using putnext
10440Sstevel@tonic-gate 			 * Fall back on waiting + getq.
10450Sstevel@tonic-gate 			 */
10460Sstevel@tonic-gate 			error = 0;
10470Sstevel@tonic-gate 		} else {
10480Sstevel@tonic-gate 			*errorp = error;
10490Sstevel@tonic-gate 			ASSERT(MUTEX_HELD(&stp->sd_lock));
10500Sstevel@tonic-gate 			return (NULL);
10510Sstevel@tonic-gate 		}
10520Sstevel@tonic-gate 		/*
10530Sstevel@tonic-gate 		 * Try a getq in case a rwnext() generated mblk
10540Sstevel@tonic-gate 		 * has bubbled up via strrput().
10550Sstevel@tonic-gate 		 */
10560Sstevel@tonic-gate 	}
10570Sstevel@tonic-gate 	*errorp = 0;
10580Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&stp->sd_lock));
10596769Sja97890 
10609491SAnders.Persson@Sun.COM 	/*
10619491SAnders.Persson@Sun.COM 	 * If we have a valid uio, try and use this as a guide for how
10629491SAnders.Persson@Sun.COM 	 * many bytes to retrieve from the queue via getq_noenab().
10639491SAnders.Persson@Sun.COM 	 * Doing this can avoid unneccesary counting of overlong
10649491SAnders.Persson@Sun.COM 	 * messages in putback(). We currently only do this for sockets
10659491SAnders.Persson@Sun.COM 	 * and only if there is no sd_rputdatafunc hook.
10669491SAnders.Persson@Sun.COM 	 *
10679491SAnders.Persson@Sun.COM 	 * The sd_rputdatafunc hook transforms the entire message
10689491SAnders.Persson@Sun.COM 	 * before any bytes in it can be given to a client. So, rbytes
10699491SAnders.Persson@Sun.COM 	 * must be 0 if there is a hook.
10709491SAnders.Persson@Sun.COM 	 */
10719491SAnders.Persson@Sun.COM 	if ((uiop != NULL) && (stp->sd_vnode->v_type == VSOCK) &&
10729491SAnders.Persson@Sun.COM 	    (stp->sd_rputdatafunc == NULL))
10739491SAnders.Persson@Sun.COM 		rbytes = uiop->uio_resid;
10749491SAnders.Persson@Sun.COM 
10759491SAnders.Persson@Sun.COM 	return (getq_noenab(q, rbytes));
10760Sstevel@tonic-gate }
10770Sstevel@tonic-gate 
10780Sstevel@tonic-gate /*
10790Sstevel@tonic-gate  * Copy out the message pointed to by `bp' into the uio pointed to by `uiop'.
10800Sstevel@tonic-gate  * If the message does not fit in the uio the remainder of it is returned;
10810Sstevel@tonic-gate  * otherwise NULL is returned.  Any embedded zero-length mblk_t's are
10820Sstevel@tonic-gate  * consumed, even if uio_resid reaches zero.  On error, `*errorp' is set to
10830Sstevel@tonic-gate  * the error code, the message is consumed, and NULL is returned.
10840Sstevel@tonic-gate  */
10850Sstevel@tonic-gate static mblk_t *
struiocopyout(mblk_t * bp,struct uio * uiop,int * errorp)10860Sstevel@tonic-gate struiocopyout(mblk_t *bp, struct uio *uiop, int *errorp)
10870Sstevel@tonic-gate {
10880Sstevel@tonic-gate 	int error;
10890Sstevel@tonic-gate 	ptrdiff_t n;
10900Sstevel@tonic-gate 	mblk_t *nbp;
10910Sstevel@tonic-gate 
10920Sstevel@tonic-gate 	ASSERT(bp->b_wptr >= bp->b_rptr);
10930Sstevel@tonic-gate 
10940Sstevel@tonic-gate 	do {
10950Sstevel@tonic-gate 		if ((n = MIN(uiop->uio_resid, MBLKL(bp))) != 0) {
10960Sstevel@tonic-gate 			ASSERT(n > 0);
10970Sstevel@tonic-gate 
10980Sstevel@tonic-gate 			error = uiomove(bp->b_rptr, n, UIO_READ, uiop);
10990Sstevel@tonic-gate 			if (error != 0) {
11000Sstevel@tonic-gate 				freemsg(bp);
11010Sstevel@tonic-gate 				*errorp = error;
11020Sstevel@tonic-gate 				return (NULL);
11030Sstevel@tonic-gate 			}
11040Sstevel@tonic-gate 		}
11050Sstevel@tonic-gate 
11060Sstevel@tonic-gate 		bp->b_rptr += n;
11070Sstevel@tonic-gate 		while (bp != NULL && (bp->b_rptr >= bp->b_wptr)) {
11080Sstevel@tonic-gate 			nbp = bp;
11090Sstevel@tonic-gate 			bp = bp->b_cont;
11100Sstevel@tonic-gate 			freeb(nbp);
11110Sstevel@tonic-gate 		}
11120Sstevel@tonic-gate 	} while (bp != NULL && uiop->uio_resid > 0);
11130Sstevel@tonic-gate 
11140Sstevel@tonic-gate 	*errorp = 0;
11150Sstevel@tonic-gate 	return (bp);
11160Sstevel@tonic-gate }
11170Sstevel@tonic-gate 
11180Sstevel@tonic-gate /*
11190Sstevel@tonic-gate  * Read a stream according to the mode flags in sd_flag:
11200Sstevel@tonic-gate  *
11210Sstevel@tonic-gate  * (default mode)		- Byte stream, msg boundaries are ignored
11220Sstevel@tonic-gate  * RD_MSGDIS (msg discard)	- Read on msg boundaries and throw away
11230Sstevel@tonic-gate  *				any data remaining in msg
11240Sstevel@tonic-gate  * RD_MSGNODIS (msg non-discard) - Read on msg boundaries and put back
11250Sstevel@tonic-gate  *				any remaining data on head of read queue
11260Sstevel@tonic-gate  *
11270Sstevel@tonic-gate  * Consume readable messages on the front of the queue until
11280Sstevel@tonic-gate  * ttolwp(curthread)->lwp_count
11290Sstevel@tonic-gate  * is satisfied, the readable messages are exhausted, or a message
11300Sstevel@tonic-gate  * boundary is reached in a message mode.  If no data was read and
11310Sstevel@tonic-gate  * the stream was not opened with the NDELAY flag, block until data arrives.
11320Sstevel@tonic-gate  * Otherwise return the data read and update the count.
11330Sstevel@tonic-gate  *
11340Sstevel@tonic-gate  * In default mode a 0 length message signifies end-of-file and terminates
11350Sstevel@tonic-gate  * a read in progress.  The 0 length message is removed from the queue
11360Sstevel@tonic-gate  * only if it is the only message read (no data is read).
11370Sstevel@tonic-gate  *
11380Sstevel@tonic-gate  * An attempt to read an M_PROTO or M_PCPROTO message results in an
11390Sstevel@tonic-gate  * EBADMSG error return, unless either RD_PROTDAT or RD_PROTDIS are set.
11400Sstevel@tonic-gate  * If RD_PROTDAT is set, M_PROTO and M_PCPROTO messages are read as data.
11410Sstevel@tonic-gate  * If RD_PROTDIS is set, the M_PROTO and M_PCPROTO parts of the message
11420Sstevel@tonic-gate  * are unlinked from and M_DATA blocks in the message, the protos are
11430Sstevel@tonic-gate  * thrown away, and the data is read.
11440Sstevel@tonic-gate  */
11450Sstevel@tonic-gate /* ARGSUSED */
11460Sstevel@tonic-gate int
strread(struct vnode * vp,struct uio * uiop,cred_t * crp)11470Sstevel@tonic-gate strread(struct vnode *vp, struct uio *uiop, cred_t *crp)
11480Sstevel@tonic-gate {
11490Sstevel@tonic-gate 	struct stdata *stp;
11500Sstevel@tonic-gate 	mblk_t *bp, *nbp;
11510Sstevel@tonic-gate 	queue_t *q;
11520Sstevel@tonic-gate 	int error = 0;
11530Sstevel@tonic-gate 	uint_t old_sd_flag;
11540Sstevel@tonic-gate 	int first;
11550Sstevel@tonic-gate 	char rflg;
11560Sstevel@tonic-gate 	uint_t mark;		/* Contains MSG*MARK and _LASTMARK */
11570Sstevel@tonic-gate #define	_LASTMARK	0x8000	/* Distinct from MSG*MARK */
11580Sstevel@tonic-gate 	short delim;
11590Sstevel@tonic-gate 	unsigned char pri = 0;
11600Sstevel@tonic-gate 	char waitflag;
11610Sstevel@tonic-gate 	unsigned char type;
11620Sstevel@tonic-gate 
11630Sstevel@tonic-gate 	TRACE_1(TR_FAC_STREAMS_FR,
11645753Sgww 	    TR_STRREAD_ENTER, "strread:%p", vp);
11650Sstevel@tonic-gate 	ASSERT(vp->v_stream);
11660Sstevel@tonic-gate 	stp = vp->v_stream;
11670Sstevel@tonic-gate 
11680Sstevel@tonic-gate 	mutex_enter(&stp->sd_lock);
11692712Snn35248 
11702712Snn35248 	if ((error = i_straccess(stp, JCREAD)) != 0) {
11712712Snn35248 		mutex_exit(&stp->sd_lock);
11722712Snn35248 		return (error);
11732712Snn35248 	}
11742712Snn35248 
11750Sstevel@tonic-gate 	if (stp->sd_flag & (STRDERR|STPLEX)) {
11760Sstevel@tonic-gate 		error = strgeterr(stp, STRDERR|STPLEX, 0);
11770Sstevel@tonic-gate 		if (error != 0) {
11780Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
11790Sstevel@tonic-gate 			return (error);
11800Sstevel@tonic-gate 		}
11810Sstevel@tonic-gate 	}
11820Sstevel@tonic-gate 
11830Sstevel@tonic-gate 	/*
11840Sstevel@tonic-gate 	 * Loop terminates when uiop->uio_resid == 0.
11850Sstevel@tonic-gate 	 */
11860Sstevel@tonic-gate 	rflg = 0;
11870Sstevel@tonic-gate 	waitflag = READWAIT;
11880Sstevel@tonic-gate 	q = _RD(stp->sd_wrq);
11890Sstevel@tonic-gate 	for (;;) {
11900Sstevel@tonic-gate 		ASSERT(MUTEX_HELD(&stp->sd_lock));
11910Sstevel@tonic-gate 		old_sd_flag = stp->sd_flag;
11920Sstevel@tonic-gate 		mark = 0;
11930Sstevel@tonic-gate 		delim = 0;
11940Sstevel@tonic-gate 		first = 1;
11950Sstevel@tonic-gate 		while ((bp = strget(stp, q, uiop, first, &error)) == NULL) {
11960Sstevel@tonic-gate 			int done = 0;
11970Sstevel@tonic-gate 
11980Sstevel@tonic-gate 			ASSERT(MUTEX_HELD(&stp->sd_lock));
11990Sstevel@tonic-gate 
12000Sstevel@tonic-gate 			if (error != 0)
12010Sstevel@tonic-gate 				goto oops;
12020Sstevel@tonic-gate 
12030Sstevel@tonic-gate 			if (stp->sd_flag & (STRHUP|STREOF)) {
12040Sstevel@tonic-gate 				goto oops;
12050Sstevel@tonic-gate 			}
12060Sstevel@tonic-gate 			if (rflg && !(stp->sd_flag & STRDELIM)) {
12070Sstevel@tonic-gate 				goto oops;
12080Sstevel@tonic-gate 			}
12090Sstevel@tonic-gate 			/*
12100Sstevel@tonic-gate 			 * If a read(fd,buf,0) has been done, there is no
12110Sstevel@tonic-gate 			 * need to sleep. We always have zero bytes to
12120Sstevel@tonic-gate 			 * return.
12130Sstevel@tonic-gate 			 */
12140Sstevel@tonic-gate 			if (uiop->uio_resid == 0) {
12150Sstevel@tonic-gate 				goto oops;
12160Sstevel@tonic-gate 			}
12170Sstevel@tonic-gate 
12180Sstevel@tonic-gate 			qbackenable(q, 0);
12190Sstevel@tonic-gate 
12200Sstevel@tonic-gate 			TRACE_3(TR_FAC_STREAMS_FR, TR_STRREAD_WAIT,
12215753Sgww 			    "strread calls strwaitq:%p, %p, %p",
12225753Sgww 			    vp, uiop, crp);
12230Sstevel@tonic-gate 			if ((error = strwaitq(stp, waitflag, uiop->uio_resid,
12240Sstevel@tonic-gate 			    uiop->uio_fmode, -1, &done)) != 0 || done) {
12250Sstevel@tonic-gate 				TRACE_3(TR_FAC_STREAMS_FR, TR_STRREAD_DONE,
12265753Sgww 				    "strread error or done:%p, %p, %p",
12275753Sgww 				    vp, uiop, crp);
12280Sstevel@tonic-gate 				if ((uiop->uio_fmode & FNDELAY) &&
12290Sstevel@tonic-gate 				    (stp->sd_flag & OLDNDELAY) &&
12300Sstevel@tonic-gate 				    (error == EAGAIN))
12310Sstevel@tonic-gate 					error = 0;
12320Sstevel@tonic-gate 				goto oops;
12330Sstevel@tonic-gate 			}
12340Sstevel@tonic-gate 			TRACE_3(TR_FAC_STREAMS_FR, TR_STRREAD_AWAKE,
12355753Sgww 			    "strread awakes:%p, %p, %p", vp, uiop, crp);
12362712Snn35248 			if ((error = i_straccess(stp, JCREAD)) != 0) {
12372712Snn35248 				goto oops;
12380Sstevel@tonic-gate 			}
12390Sstevel@tonic-gate 			first = 0;
12400Sstevel@tonic-gate 		}
12416707Sbrutus 
12420Sstevel@tonic-gate 		ASSERT(MUTEX_HELD(&stp->sd_lock));
12430Sstevel@tonic-gate 		ASSERT(bp);
12440Sstevel@tonic-gate 		pri = bp->b_band;
12450Sstevel@tonic-gate 		/*
12460Sstevel@tonic-gate 		 * Extract any mark information. If the message is not
12470Sstevel@tonic-gate 		 * completely consumed this information will be put in the mblk
12480Sstevel@tonic-gate 		 * that is putback.
12490Sstevel@tonic-gate 		 * If MSGMARKNEXT is set and the message is completely consumed
12500Sstevel@tonic-gate 		 * the STRATMARK flag will be set below. Likewise, if
12510Sstevel@tonic-gate 		 * MSGNOTMARKNEXT is set and the message is
12520Sstevel@tonic-gate 		 * completely consumed STRNOTATMARK will be set.
12530Sstevel@tonic-gate 		 *
12540Sstevel@tonic-gate 		 * For some unknown reason strread only breaks the read at the
12550Sstevel@tonic-gate 		 * last mark.
12560Sstevel@tonic-gate 		 */
12570Sstevel@tonic-gate 		mark = bp->b_flag & (MSGMARK | MSGMARKNEXT | MSGNOTMARKNEXT);
12580Sstevel@tonic-gate 		ASSERT((mark & (MSGMARKNEXT|MSGNOTMARKNEXT)) !=
12595753Sgww 		    (MSGMARKNEXT|MSGNOTMARKNEXT));
12600Sstevel@tonic-gate 		if (mark != 0 && bp == stp->sd_mark) {
12610Sstevel@tonic-gate 			if (rflg) {
12620Sstevel@tonic-gate 				putback(stp, q, bp, pri);
12630Sstevel@tonic-gate 				goto oops;
12640Sstevel@tonic-gate 			}
12650Sstevel@tonic-gate 			mark |= _LASTMARK;
12660Sstevel@tonic-gate 			stp->sd_mark = NULL;
12670Sstevel@tonic-gate 		}
12680Sstevel@tonic-gate 		if ((stp->sd_flag & STRDELIM) && (bp->b_flag & MSGDELIM))
12690Sstevel@tonic-gate 			delim = 1;
12700Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
12710Sstevel@tonic-gate 
12720Sstevel@tonic-gate 		if (STREAM_NEEDSERVICE(stp))
12730Sstevel@tonic-gate 			stream_runservice(stp);
12740Sstevel@tonic-gate 
12750Sstevel@tonic-gate 		type = bp->b_datap->db_type;
12760Sstevel@tonic-gate 
12770Sstevel@tonic-gate 		switch (type) {
12780Sstevel@tonic-gate 
12790Sstevel@tonic-gate 		case M_DATA:
12800Sstevel@tonic-gate ismdata:
12810Sstevel@tonic-gate 			if (msgnodata(bp)) {
12820Sstevel@tonic-gate 				if (mark || delim) {
12830Sstevel@tonic-gate 					freemsg(bp);
12840Sstevel@tonic-gate 				} else if (rflg) {
12850Sstevel@tonic-gate 
12860Sstevel@tonic-gate 					/*
12870Sstevel@tonic-gate 					 * If already read data put zero
12880Sstevel@tonic-gate 					 * length message back on queue else
12890Sstevel@tonic-gate 					 * free msg and return 0.
12900Sstevel@tonic-gate 					 */
12910Sstevel@tonic-gate 					bp->b_band = pri;
12920Sstevel@tonic-gate 					mutex_enter(&stp->sd_lock);
12930Sstevel@tonic-gate 					putback(stp, q, bp, pri);
12940Sstevel@tonic-gate 					mutex_exit(&stp->sd_lock);
12950Sstevel@tonic-gate 				} else {
12960Sstevel@tonic-gate 					freemsg(bp);
12970Sstevel@tonic-gate 				}
12980Sstevel@tonic-gate 				error =  0;
12990Sstevel@tonic-gate 				goto oops1;
13000Sstevel@tonic-gate 			}
13010Sstevel@tonic-gate 
13020Sstevel@tonic-gate 			rflg = 1;
13030Sstevel@tonic-gate 			waitflag |= NOINTR;
13040Sstevel@tonic-gate 			bp = struiocopyout(bp, uiop, &error);
13050Sstevel@tonic-gate 			if (error != 0)
13060Sstevel@tonic-gate 				goto oops1;
13070Sstevel@tonic-gate 
13080Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
13090Sstevel@tonic-gate 			if (bp) {
13100Sstevel@tonic-gate 				/*
13110Sstevel@tonic-gate 				 * Have remaining data in message.
13120Sstevel@tonic-gate 				 * Free msg if in discard mode.
13130Sstevel@tonic-gate 				 */
13140Sstevel@tonic-gate 				if (stp->sd_read_opt & RD_MSGDIS) {
13150Sstevel@tonic-gate 					freemsg(bp);
13160Sstevel@tonic-gate 				} else {
13170Sstevel@tonic-gate 					bp->b_band = pri;
13180Sstevel@tonic-gate 					if ((mark & _LASTMARK) &&
13190Sstevel@tonic-gate 					    (stp->sd_mark == NULL))
13200Sstevel@tonic-gate 						stp->sd_mark = bp;
13210Sstevel@tonic-gate 					bp->b_flag |= mark & ~_LASTMARK;
13220Sstevel@tonic-gate 					if (delim)
13230Sstevel@tonic-gate 						bp->b_flag |= MSGDELIM;
13240Sstevel@tonic-gate 					if (msgnodata(bp))
13250Sstevel@tonic-gate 						freemsg(bp);
13260Sstevel@tonic-gate 					else
13270Sstevel@tonic-gate 						putback(stp, q, bp, pri);
13280Sstevel@tonic-gate 				}
13290Sstevel@tonic-gate 			} else {
13300Sstevel@tonic-gate 				/*
13310Sstevel@tonic-gate 				 * Consumed the complete message.
13320Sstevel@tonic-gate 				 * Move the MSG*MARKNEXT information
13330Sstevel@tonic-gate 				 * to the stream head just in case
13340Sstevel@tonic-gate 				 * the read queue becomes empty.
13350Sstevel@tonic-gate 				 *
13360Sstevel@tonic-gate 				 * If the stream head was at the mark
13370Sstevel@tonic-gate 				 * (STRATMARK) before we dropped sd_lock above
13380Sstevel@tonic-gate 				 * and some data was consumed then we have
13390Sstevel@tonic-gate 				 * moved past the mark thus STRATMARK is
13400Sstevel@tonic-gate 				 * cleared. However, if a message arrived in
13410Sstevel@tonic-gate 				 * strrput during the copyout above causing
13420Sstevel@tonic-gate 				 * STRATMARK to be set we can not clear that
13430Sstevel@tonic-gate 				 * flag.
13440Sstevel@tonic-gate 				 */
13450Sstevel@tonic-gate 				if (mark &
13460Sstevel@tonic-gate 				    (MSGMARKNEXT|MSGNOTMARKNEXT|MSGMARK)) {
13470Sstevel@tonic-gate 					if (mark & MSGMARKNEXT) {
13480Sstevel@tonic-gate 						stp->sd_flag &= ~STRNOTATMARK;
13490Sstevel@tonic-gate 						stp->sd_flag |= STRATMARK;
13500Sstevel@tonic-gate 					} else if (mark & MSGNOTMARKNEXT) {
13510Sstevel@tonic-gate 						stp->sd_flag &= ~STRATMARK;
13520Sstevel@tonic-gate 						stp->sd_flag |= STRNOTATMARK;
13530Sstevel@tonic-gate 					} else {
13540Sstevel@tonic-gate 						stp->sd_flag &=
13550Sstevel@tonic-gate 						    ~(STRATMARK|STRNOTATMARK);
13560Sstevel@tonic-gate 					}
13570Sstevel@tonic-gate 				} else if (rflg && (old_sd_flag & STRATMARK)) {
13580Sstevel@tonic-gate 					stp->sd_flag &= ~STRATMARK;
13590Sstevel@tonic-gate 				}
13600Sstevel@tonic-gate 			}
13610Sstevel@tonic-gate 
13620Sstevel@tonic-gate 			/*
13630Sstevel@tonic-gate 			 * Check for signal messages at the front of the read
13640Sstevel@tonic-gate 			 * queue and generate the signal(s) if appropriate.
13650Sstevel@tonic-gate 			 * The only signal that can be on queue is M_SIG at
13660Sstevel@tonic-gate 			 * this point.
13670Sstevel@tonic-gate 			 */
13680Sstevel@tonic-gate 			while ((((bp = q->q_first)) != NULL) &&
13695753Sgww 			    (bp->b_datap->db_type == M_SIG)) {
13706769Sja97890 				bp = getq_noenab(q, 0);
13710Sstevel@tonic-gate 				/*
13720Sstevel@tonic-gate 				 * sd_lock is held so the content of the
13730Sstevel@tonic-gate 				 * read queue can not change.
13740Sstevel@tonic-gate 				 */
13758752SPeter.Memishian@Sun.COM 				ASSERT(bp != NULL && DB_TYPE(bp) == M_SIG);
13768752SPeter.Memishian@Sun.COM 				strsignal_nolock(stp, *bp->b_rptr, bp->b_band);
13770Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
13780Sstevel@tonic-gate 				freemsg(bp);
13790Sstevel@tonic-gate 				if (STREAM_NEEDSERVICE(stp))
13800Sstevel@tonic-gate 					stream_runservice(stp);
13810Sstevel@tonic-gate 				mutex_enter(&stp->sd_lock);
13820Sstevel@tonic-gate 			}
13830Sstevel@tonic-gate 
13840Sstevel@tonic-gate 			if ((uiop->uio_resid == 0) || (mark & _LASTMARK) ||
13850Sstevel@tonic-gate 			    delim ||
13860Sstevel@tonic-gate 			    (stp->sd_read_opt & (RD_MSGDIS|RD_MSGNODIS))) {
13870Sstevel@tonic-gate 				goto oops;
13880Sstevel@tonic-gate 			}
13890Sstevel@tonic-gate 			continue;
13900Sstevel@tonic-gate 
13910Sstevel@tonic-gate 		case M_SIG:
13920Sstevel@tonic-gate 			strsignal(stp, *bp->b_rptr, (int32_t)bp->b_band);
13930Sstevel@tonic-gate 			freemsg(bp);
13940Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
13950Sstevel@tonic-gate 			continue;
13960Sstevel@tonic-gate 
13970Sstevel@tonic-gate 		case M_PROTO:
13980Sstevel@tonic-gate 		case M_PCPROTO:
13990Sstevel@tonic-gate 			/*
14000Sstevel@tonic-gate 			 * Only data messages are readable.
14010Sstevel@tonic-gate 			 * Any others generate an error, unless
14020Sstevel@tonic-gate 			 * RD_PROTDIS or RD_PROTDAT is set.
14030Sstevel@tonic-gate 			 */
14040Sstevel@tonic-gate 			if (stp->sd_read_opt & RD_PROTDAT) {
14050Sstevel@tonic-gate 				for (nbp = bp; nbp; nbp = nbp->b_next) {
14065753Sgww 					if ((nbp->b_datap->db_type ==
14075753Sgww 					    M_PROTO) ||
14085753Sgww 					    (nbp->b_datap->db_type ==
14095753Sgww 					    M_PCPROTO)) {
14105753Sgww 						nbp->b_datap->db_type = M_DATA;
14115753Sgww 					} else {
14125753Sgww 						break;
14135753Sgww 					}
14140Sstevel@tonic-gate 				}
14150Sstevel@tonic-gate 				/*
14160Sstevel@tonic-gate 				 * clear stream head hi pri flag based on
14170Sstevel@tonic-gate 				 * first message
14180Sstevel@tonic-gate 				 */
14190Sstevel@tonic-gate 				if (type == M_PCPROTO) {
14200Sstevel@tonic-gate 					mutex_enter(&stp->sd_lock);
14210Sstevel@tonic-gate 					stp->sd_flag &= ~STRPRI;
14220Sstevel@tonic-gate 					mutex_exit(&stp->sd_lock);
14230Sstevel@tonic-gate 				}
14240Sstevel@tonic-gate 				goto ismdata;
14250Sstevel@tonic-gate 			} else if (stp->sd_read_opt & RD_PROTDIS) {
14260Sstevel@tonic-gate 				/*
14270Sstevel@tonic-gate 				 * discard non-data messages
14280Sstevel@tonic-gate 				 */
14290Sstevel@tonic-gate 				while (bp &&
14300Sstevel@tonic-gate 				    ((bp->b_datap->db_type == M_PROTO) ||
14310Sstevel@tonic-gate 				    (bp->b_datap->db_type == M_PCPROTO))) {
14320Sstevel@tonic-gate 					nbp = unlinkb(bp);
14330Sstevel@tonic-gate 					freeb(bp);
14340Sstevel@tonic-gate 					bp = nbp;
14350Sstevel@tonic-gate 				}
14360Sstevel@tonic-gate 				/*
14370Sstevel@tonic-gate 				 * clear stream head hi pri flag based on
14380Sstevel@tonic-gate 				 * first message
14390Sstevel@tonic-gate 				 */
14400Sstevel@tonic-gate 				if (type == M_PCPROTO) {
14410Sstevel@tonic-gate 					mutex_enter(&stp->sd_lock);
14420Sstevel@tonic-gate 					stp->sd_flag &= ~STRPRI;
14430Sstevel@tonic-gate 					mutex_exit(&stp->sd_lock);
14440Sstevel@tonic-gate 				}
14450Sstevel@tonic-gate 				if (bp) {
14460Sstevel@tonic-gate 					bp->b_band = pri;
14470Sstevel@tonic-gate 					goto ismdata;
14480Sstevel@tonic-gate 				} else {
14490Sstevel@tonic-gate 					break;
14500Sstevel@tonic-gate 				}
14510Sstevel@tonic-gate 			}
14520Sstevel@tonic-gate 			/* FALLTHRU */
14530Sstevel@tonic-gate 		case M_PASSFP:
14540Sstevel@tonic-gate 			if ((bp->b_datap->db_type == M_PASSFP) &&
14550Sstevel@tonic-gate 			    (stp->sd_read_opt & RD_PROTDIS)) {
14560Sstevel@tonic-gate 				freemsg(bp);
14570Sstevel@tonic-gate 				break;
14580Sstevel@tonic-gate 			}
14590Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
14600Sstevel@tonic-gate 			putback(stp, q, bp, pri);
14610Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
14620Sstevel@tonic-gate 			if (rflg == 0)
14630Sstevel@tonic-gate 				error = EBADMSG;
14640Sstevel@tonic-gate 			goto oops1;
14650Sstevel@tonic-gate 
14660Sstevel@tonic-gate 		default:
14670Sstevel@tonic-gate 			/*
14680Sstevel@tonic-gate 			 * Garbage on stream head read queue.
14690Sstevel@tonic-gate 			 */
14700Sstevel@tonic-gate 			cmn_err(CE_WARN, "bad %x found at stream head\n",
14715753Sgww 			    bp->b_datap->db_type);
14720Sstevel@tonic-gate 			freemsg(bp);
14730Sstevel@tonic-gate 			goto oops1;
14740Sstevel@tonic-gate 		}
14750Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
14760Sstevel@tonic-gate 	}
14770Sstevel@tonic-gate oops:
14780Sstevel@tonic-gate 	mutex_exit(&stp->sd_lock);
14790Sstevel@tonic-gate oops1:
14800Sstevel@tonic-gate 	qbackenable(q, pri);
14810Sstevel@tonic-gate 	return (error);
14820Sstevel@tonic-gate #undef	_LASTMARK
14830Sstevel@tonic-gate }
14840Sstevel@tonic-gate 
14850Sstevel@tonic-gate /*
14860Sstevel@tonic-gate  * Default processing of M_PROTO/M_PCPROTO messages.
14870Sstevel@tonic-gate  * Determine which wakeups and signals are needed.
14880Sstevel@tonic-gate  * This can be replaced by a user-specified procedure for kernel users
14890Sstevel@tonic-gate  * of STREAMS.
14900Sstevel@tonic-gate  */
14910Sstevel@tonic-gate /* ARGSUSED */
14920Sstevel@tonic-gate mblk_t *
strrput_proto(vnode_t * vp,mblk_t * mp,strwakeup_t * wakeups,strsigset_t * firstmsgsigs,strsigset_t * allmsgsigs,strpollset_t * pollwakeups)14930Sstevel@tonic-gate strrput_proto(vnode_t *vp, mblk_t *mp,
14940Sstevel@tonic-gate     strwakeup_t *wakeups, strsigset_t *firstmsgsigs,
14950Sstevel@tonic-gate     strsigset_t *allmsgsigs, strpollset_t *pollwakeups)
14960Sstevel@tonic-gate {
14970Sstevel@tonic-gate 	*wakeups = RSLEEP;
14980Sstevel@tonic-gate 	*allmsgsigs = 0;
14990Sstevel@tonic-gate 
15000Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
15010Sstevel@tonic-gate 	case M_PROTO:
15020Sstevel@tonic-gate 		if (mp->b_band == 0) {
15030Sstevel@tonic-gate 			*firstmsgsigs = S_INPUT | S_RDNORM;
15040Sstevel@tonic-gate 			*pollwakeups = POLLIN | POLLRDNORM;
15050Sstevel@tonic-gate 		} else {
15060Sstevel@tonic-gate 			*firstmsgsigs = S_INPUT | S_RDBAND;
15070Sstevel@tonic-gate 			*pollwakeups = POLLIN | POLLRDBAND;
15080Sstevel@tonic-gate 		}
15090Sstevel@tonic-gate 		break;
15100Sstevel@tonic-gate 	case M_PCPROTO:
15110Sstevel@tonic-gate 		*firstmsgsigs = S_HIPRI;
15120Sstevel@tonic-gate 		*pollwakeups = POLLPRI;
15130Sstevel@tonic-gate 		break;
15140Sstevel@tonic-gate 	}
15150Sstevel@tonic-gate 	return (mp);
15160Sstevel@tonic-gate }
15170Sstevel@tonic-gate 
15180Sstevel@tonic-gate /*
15190Sstevel@tonic-gate  * Default processing of everything but M_DATA, M_PROTO, M_PCPROTO and
15200Sstevel@tonic-gate  * M_PASSFP messages.
15210Sstevel@tonic-gate  * Determine which wakeups and signals are needed.
15220Sstevel@tonic-gate  * This can be replaced by a user-specified procedure for kernel users
15230Sstevel@tonic-gate  * of STREAMS.
15240Sstevel@tonic-gate  */
15250Sstevel@tonic-gate /* ARGSUSED */
15260Sstevel@tonic-gate mblk_t *
strrput_misc(vnode_t * vp,mblk_t * mp,strwakeup_t * wakeups,strsigset_t * firstmsgsigs,strsigset_t * allmsgsigs,strpollset_t * pollwakeups)15270Sstevel@tonic-gate strrput_misc(vnode_t *vp, mblk_t *mp,
15280Sstevel@tonic-gate     strwakeup_t *wakeups, strsigset_t *firstmsgsigs,
15290Sstevel@tonic-gate     strsigset_t *allmsgsigs, strpollset_t *pollwakeups)
15300Sstevel@tonic-gate {
15310Sstevel@tonic-gate 	*wakeups = 0;
15320Sstevel@tonic-gate 	*firstmsgsigs = 0;
15330Sstevel@tonic-gate 	*allmsgsigs = 0;
15340Sstevel@tonic-gate 	*pollwakeups = 0;
15350Sstevel@tonic-gate 	return (mp);
15360Sstevel@tonic-gate }
15370Sstevel@tonic-gate 
15380Sstevel@tonic-gate /*
15390Sstevel@tonic-gate  * Stream read put procedure.  Called from downstream driver/module
15400Sstevel@tonic-gate  * with messages for the stream head.  Data, protocol, and in-stream
15410Sstevel@tonic-gate  * signal messages are placed on the queue, others are handled directly.
15420Sstevel@tonic-gate  */
15430Sstevel@tonic-gate int
strrput(queue_t * q,mblk_t * bp)15440Sstevel@tonic-gate strrput(queue_t *q, mblk_t *bp)
15450Sstevel@tonic-gate {
15460Sstevel@tonic-gate 	struct stdata	*stp;
15470Sstevel@tonic-gate 	ulong_t		rput_opt;
15480Sstevel@tonic-gate 	strwakeup_t	wakeups;
15490Sstevel@tonic-gate 	strsigset_t	firstmsgsigs;	/* Signals if first message on queue */
15500Sstevel@tonic-gate 	strsigset_t	allmsgsigs;	/* Signals for all messages */
15510Sstevel@tonic-gate 	strsigset_t	signals;	/* Signals events to generate */
15520Sstevel@tonic-gate 	strpollset_t	pollwakeups;
15530Sstevel@tonic-gate 	mblk_t		*nextbp;
15540Sstevel@tonic-gate 	uchar_t		band = 0;
15550Sstevel@tonic-gate 	int		hipri_sig;
15560Sstevel@tonic-gate 
15570Sstevel@tonic-gate 	stp = (struct stdata *)q->q_ptr;
15580Sstevel@tonic-gate 	/*
15590Sstevel@tonic-gate 	 * Use rput_opt for optimized access to the SR_ flags except
15600Sstevel@tonic-gate 	 * SR_POLLIN. That flag has to be checked under sd_lock since it
15610Sstevel@tonic-gate 	 * is modified by strpoll().
15620Sstevel@tonic-gate 	 */
15630Sstevel@tonic-gate 	rput_opt = stp->sd_rput_opt;
15640Sstevel@tonic-gate 
15650Sstevel@tonic-gate 	ASSERT(qclaimed(q));
15660Sstevel@tonic-gate 	TRACE_2(TR_FAC_STREAMS_FR, TR_STRRPUT_ENTER,
15675753Sgww 	    "strrput called with message type:q %p bp %p", q, bp);
15680Sstevel@tonic-gate 
15690Sstevel@tonic-gate 	/*
15700Sstevel@tonic-gate 	 * Perform initial processing and pass to the parameterized functions.
15710Sstevel@tonic-gate 	 */
15720Sstevel@tonic-gate 	ASSERT(bp->b_next == NULL);
15730Sstevel@tonic-gate 
15740Sstevel@tonic-gate 	switch (bp->b_datap->db_type) {
15750Sstevel@tonic-gate 	case M_DATA:
15760Sstevel@tonic-gate 		/*
15770Sstevel@tonic-gate 		 * sockfs is the only consumer of STREOF and when it is set,
15780Sstevel@tonic-gate 		 * it implies that the receiver is not interested in receiving
15790Sstevel@tonic-gate 		 * any more data, hence the mblk is freed to prevent unnecessary
15800Sstevel@tonic-gate 		 * message queueing at the stream head.
15810Sstevel@tonic-gate 		 */
15820Sstevel@tonic-gate 		if (stp->sd_flag == STREOF) {
15830Sstevel@tonic-gate 			freemsg(bp);
15840Sstevel@tonic-gate 			return (0);
15850Sstevel@tonic-gate 		}
15860Sstevel@tonic-gate 		if ((rput_opt & SR_IGN_ZEROLEN) &&
15870Sstevel@tonic-gate 		    bp->b_rptr == bp->b_wptr && msgnodata(bp)) {
15880Sstevel@tonic-gate 			/*
15890Sstevel@tonic-gate 			 * Ignore zero-length M_DATA messages. These might be
15900Sstevel@tonic-gate 			 * generated by some transports.
15910Sstevel@tonic-gate 			 * The zero-length M_DATA messages, even if they
15920Sstevel@tonic-gate 			 * are ignored, should effect the atmark tracking and
15930Sstevel@tonic-gate 			 * should wake up a thread sleeping in strwaitmark.
15940Sstevel@tonic-gate 			 */
15950Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
15960Sstevel@tonic-gate 			if (bp->b_flag & MSGMARKNEXT) {
15970Sstevel@tonic-gate 				/*
15980Sstevel@tonic-gate 				 * Record the position of the mark either
15990Sstevel@tonic-gate 				 * in q_last or in STRATMARK.
16000Sstevel@tonic-gate 				 */
16010Sstevel@tonic-gate 				if (q->q_last != NULL) {
16020Sstevel@tonic-gate 					q->q_last->b_flag &= ~MSGNOTMARKNEXT;
16030Sstevel@tonic-gate 					q->q_last->b_flag |= MSGMARKNEXT;
16040Sstevel@tonic-gate 				} else {
16050Sstevel@tonic-gate 					stp->sd_flag &= ~STRNOTATMARK;
16060Sstevel@tonic-gate 					stp->sd_flag |= STRATMARK;
16070Sstevel@tonic-gate 				}
16080Sstevel@tonic-gate 			} else if (bp->b_flag & MSGNOTMARKNEXT) {
16090Sstevel@tonic-gate 				/*
16100Sstevel@tonic-gate 				 * Record that this is not the position of
16110Sstevel@tonic-gate 				 * the mark either in q_last or in
16120Sstevel@tonic-gate 				 * STRNOTATMARK.
16130Sstevel@tonic-gate 				 */
16140Sstevel@tonic-gate 				if (q->q_last != NULL) {
16150Sstevel@tonic-gate 					q->q_last->b_flag &= ~MSGMARKNEXT;
16160Sstevel@tonic-gate 					q->q_last->b_flag |= MSGNOTMARKNEXT;
16170Sstevel@tonic-gate 				} else {
16180Sstevel@tonic-gate 					stp->sd_flag &= ~STRATMARK;
16190Sstevel@tonic-gate 					stp->sd_flag |= STRNOTATMARK;
16200Sstevel@tonic-gate 				}
16210Sstevel@tonic-gate 			}
16220Sstevel@tonic-gate 			if (stp->sd_flag & RSLEEP) {
16230Sstevel@tonic-gate 				stp->sd_flag &= ~RSLEEP;
16240Sstevel@tonic-gate 				cv_broadcast(&q->q_wait);
16250Sstevel@tonic-gate 			}
16260Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
16270Sstevel@tonic-gate 			freemsg(bp);
16280Sstevel@tonic-gate 			return (0);
16290Sstevel@tonic-gate 		}
16300Sstevel@tonic-gate 		wakeups = RSLEEP;
16310Sstevel@tonic-gate 		if (bp->b_band == 0) {
16320Sstevel@tonic-gate 			firstmsgsigs = S_INPUT | S_RDNORM;
16330Sstevel@tonic-gate 			pollwakeups = POLLIN | POLLRDNORM;
16340Sstevel@tonic-gate 		} else {
16350Sstevel@tonic-gate 			firstmsgsigs = S_INPUT | S_RDBAND;
16360Sstevel@tonic-gate 			pollwakeups = POLLIN | POLLRDBAND;
16370Sstevel@tonic-gate 		}
16380Sstevel@tonic-gate 		if (rput_opt & SR_SIGALLDATA)
16390Sstevel@tonic-gate 			allmsgsigs = firstmsgsigs;
16400Sstevel@tonic-gate 		else
16410Sstevel@tonic-gate 			allmsgsigs = 0;
16420Sstevel@tonic-gate 
16430Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
16440Sstevel@tonic-gate 		if ((rput_opt & SR_CONSOL_DATA) &&
16454683Sja97890 		    (q->q_last != NULL) &&
16460Sstevel@tonic-gate 		    (bp->b_flag & (MSGMARK|MSGDELIM)) == 0) {
16470Sstevel@tonic-gate 			/*
16484683Sja97890 			 * Consolidate an M_DATA message onto an M_DATA,
16490Sstevel@tonic-gate 			 * M_PROTO, or M_PCPROTO by merging it with q_last.
16500Sstevel@tonic-gate 			 * The consolidation does not take place if
16510Sstevel@tonic-gate 			 * the old message is marked with either of the
16520Sstevel@tonic-gate 			 * marks or the delim flag or if the new
16530Sstevel@tonic-gate 			 * message is marked with MSGMARK. The MSGMARK
16540Sstevel@tonic-gate 			 * check is needed to handle the odd semantics of
16550Sstevel@tonic-gate 			 * MSGMARK where essentially the whole message
16560Sstevel@tonic-gate 			 * is to be treated as marked.
16570Sstevel@tonic-gate 			 * Carry any MSGMARKNEXT  and MSGNOTMARKNEXT from the
16580Sstevel@tonic-gate 			 * new message to the front of the b_cont chain.
16590Sstevel@tonic-gate 			 */
16604683Sja97890 			mblk_t *lbp = q->q_last;
16614683Sja97890 			unsigned char db_type = lbp->b_datap->db_type;
16624683Sja97890 
16634683Sja97890 			if ((db_type == M_DATA || db_type == M_PROTO ||
16644683Sja97890 			    db_type == M_PCPROTO) &&
16654683Sja97890 			    !(lbp->b_flag & (MSGDELIM|MSGMARK|MSGMARKNEXT))) {
16660Sstevel@tonic-gate 				rmvq_noenab(q, lbp);
16670Sstevel@tonic-gate 				/*
16680Sstevel@tonic-gate 				 * The first message in the b_cont list
16690Sstevel@tonic-gate 				 * tracks MSGMARKNEXT and MSGNOTMARKNEXT.
16700Sstevel@tonic-gate 				 * We need to handle the case where we
16714683Sja97890 				 * are appending:
16720Sstevel@tonic-gate 				 *
16730Sstevel@tonic-gate 				 * 1) a MSGMARKNEXT to a MSGNOTMARKNEXT.
16740Sstevel@tonic-gate 				 * 2) a MSGMARKNEXT to a plain message.
16750Sstevel@tonic-gate 				 * 3) a MSGNOTMARKNEXT to a plain message
16760Sstevel@tonic-gate 				 * 4) a MSGNOTMARKNEXT to a MSGNOTMARKNEXT
16770Sstevel@tonic-gate 				 *    message.
16780Sstevel@tonic-gate 				 *
16790Sstevel@tonic-gate 				 * Thus we never append a MSGMARKNEXT or
16800Sstevel@tonic-gate 				 * MSGNOTMARKNEXT to a MSGMARKNEXT message.
16810Sstevel@tonic-gate 				 */
16820Sstevel@tonic-gate 				if (bp->b_flag & MSGMARKNEXT) {
16830Sstevel@tonic-gate 					lbp->b_flag |= MSGMARKNEXT;
16840Sstevel@tonic-gate 					lbp->b_flag &= ~MSGNOTMARKNEXT;
16850Sstevel@tonic-gate 					bp->b_flag &= ~MSGMARKNEXT;
16860Sstevel@tonic-gate 				} else if (bp->b_flag & MSGNOTMARKNEXT) {
16870Sstevel@tonic-gate 					lbp->b_flag |= MSGNOTMARKNEXT;
16880Sstevel@tonic-gate 					bp->b_flag &= ~MSGNOTMARKNEXT;
16890Sstevel@tonic-gate 				}
16900Sstevel@tonic-gate 
16910Sstevel@tonic-gate 				linkb(lbp, bp);
16920Sstevel@tonic-gate 				bp = lbp;
16930Sstevel@tonic-gate 				/*
16940Sstevel@tonic-gate 				 * The new message logically isn't the first
16950Sstevel@tonic-gate 				 * even though the q_first check below thinks
16960Sstevel@tonic-gate 				 * it is. Clear the firstmsgsigs to make it
16970Sstevel@tonic-gate 				 * not appear to be first.
16980Sstevel@tonic-gate 				 */
16990Sstevel@tonic-gate 				firstmsgsigs = 0;
17000Sstevel@tonic-gate 			}
17010Sstevel@tonic-gate 		}
17020Sstevel@tonic-gate 		break;
17030Sstevel@tonic-gate 
17040Sstevel@tonic-gate 	case M_PASSFP:
17050Sstevel@tonic-gate 		wakeups = RSLEEP;
17060Sstevel@tonic-gate 		allmsgsigs = 0;
17070Sstevel@tonic-gate 		if (bp->b_band == 0) {
17080Sstevel@tonic-gate 			firstmsgsigs = S_INPUT | S_RDNORM;
17090Sstevel@tonic-gate 			pollwakeups = POLLIN | POLLRDNORM;
17100Sstevel@tonic-gate 		} else {
17110Sstevel@tonic-gate 			firstmsgsigs = S_INPUT | S_RDBAND;
17120Sstevel@tonic-gate 			pollwakeups = POLLIN | POLLRDBAND;
17130Sstevel@tonic-gate 		}
17140Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
17150Sstevel@tonic-gate 		break;
17160Sstevel@tonic-gate 
17170Sstevel@tonic-gate 	case M_PROTO:
17180Sstevel@tonic-gate 	case M_PCPROTO:
17190Sstevel@tonic-gate 		ASSERT(stp->sd_rprotofunc != NULL);
17200Sstevel@tonic-gate 		bp = (stp->sd_rprotofunc)(stp->sd_vnode, bp,
17215753Sgww 		    &wakeups, &firstmsgsigs, &allmsgsigs, &pollwakeups);
17220Sstevel@tonic-gate #define	ALLSIG	(S_INPUT|S_HIPRI|S_OUTPUT|S_MSG|S_ERROR|S_HANGUP|S_RDNORM|\
17230Sstevel@tonic-gate 		S_WRNORM|S_RDBAND|S_WRBAND|S_BANDURG)
17240Sstevel@tonic-gate #define	ALLPOLL	(POLLIN|POLLPRI|POLLOUT|POLLRDNORM|POLLWRNORM|POLLRDBAND|\
17250Sstevel@tonic-gate 		POLLWRBAND)
17260Sstevel@tonic-gate 
17270Sstevel@tonic-gate 		ASSERT((wakeups & ~(RSLEEP|WSLEEP)) == 0);
17280Sstevel@tonic-gate 		ASSERT((firstmsgsigs & ~ALLSIG) == 0);
17290Sstevel@tonic-gate 		ASSERT((allmsgsigs & ~ALLSIG) == 0);
17300Sstevel@tonic-gate 		ASSERT((pollwakeups & ~ALLPOLL) == 0);
17310Sstevel@tonic-gate 
17320Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
17330Sstevel@tonic-gate 		break;
17340Sstevel@tonic-gate 
17350Sstevel@tonic-gate 	default:
17360Sstevel@tonic-gate 		ASSERT(stp->sd_rmiscfunc != NULL);
17370Sstevel@tonic-gate 		bp = (stp->sd_rmiscfunc)(stp->sd_vnode, bp,
17385753Sgww 		    &wakeups, &firstmsgsigs, &allmsgsigs, &pollwakeups);
17390Sstevel@tonic-gate 		ASSERT((wakeups & ~(RSLEEP|WSLEEP)) == 0);
17400Sstevel@tonic-gate 		ASSERT((firstmsgsigs & ~ALLSIG) == 0);
17410Sstevel@tonic-gate 		ASSERT((allmsgsigs & ~ALLSIG) == 0);
17420Sstevel@tonic-gate 		ASSERT((pollwakeups & ~ALLPOLL) == 0);
17430Sstevel@tonic-gate #undef	ALLSIG
17440Sstevel@tonic-gate #undef	ALLPOLL
17450Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
17460Sstevel@tonic-gate 		break;
17470Sstevel@tonic-gate 	}
17480Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&stp->sd_lock));
17490Sstevel@tonic-gate 
17500Sstevel@tonic-gate 	/* By default generate superset of signals */
17510Sstevel@tonic-gate 	signals = (firstmsgsigs | allmsgsigs);
17520Sstevel@tonic-gate 
17530Sstevel@tonic-gate 	/*
17540Sstevel@tonic-gate 	 * The  proto and misc functions can return multiple messages
17550Sstevel@tonic-gate 	 * as a b_next chain. Such messages are processed separately.
17560Sstevel@tonic-gate 	 */
17570Sstevel@tonic-gate one_more:
17580Sstevel@tonic-gate 	hipri_sig = 0;
17590Sstevel@tonic-gate 	if (bp == NULL) {
17600Sstevel@tonic-gate 		nextbp = NULL;
17610Sstevel@tonic-gate 	} else {
17620Sstevel@tonic-gate 		nextbp = bp->b_next;
17630Sstevel@tonic-gate 		bp->b_next = NULL;
17640Sstevel@tonic-gate 
17650Sstevel@tonic-gate 		switch (bp->b_datap->db_type) {
17660Sstevel@tonic-gate 		case M_PCPROTO:
17670Sstevel@tonic-gate 			/*
17680Sstevel@tonic-gate 			 * Only one priority protocol message is allowed at the
17690Sstevel@tonic-gate 			 * stream head at a time.
17700Sstevel@tonic-gate 			 */
17710Sstevel@tonic-gate 			if (stp->sd_flag & STRPRI) {
17720Sstevel@tonic-gate 				TRACE_0(TR_FAC_STREAMS_FR, TR_STRRPUT_PROTERR,
17730Sstevel@tonic-gate 				    "M_PCPROTO already at head");
17740Sstevel@tonic-gate 				freemsg(bp);
17750Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
17760Sstevel@tonic-gate 				goto done;
17770Sstevel@tonic-gate 			}
17780Sstevel@tonic-gate 			stp->sd_flag |= STRPRI;
17790Sstevel@tonic-gate 			hipri_sig = 1;
17800Sstevel@tonic-gate 			/* FALLTHRU */
17810Sstevel@tonic-gate 		case M_DATA:
17820Sstevel@tonic-gate 		case M_PROTO:
17830Sstevel@tonic-gate 		case M_PASSFP:
17840Sstevel@tonic-gate 			band = bp->b_band;
17850Sstevel@tonic-gate 			/*
17860Sstevel@tonic-gate 			 * Marking doesn't work well when messages
17870Sstevel@tonic-gate 			 * are marked in more than one band.  We only
17880Sstevel@tonic-gate 			 * remember the last message received, even if
17890Sstevel@tonic-gate 			 * it is placed on the queue ahead of other
17900Sstevel@tonic-gate 			 * marked messages.
17910Sstevel@tonic-gate 			 */
17920Sstevel@tonic-gate 			if (bp->b_flag & MSGMARK)
17930Sstevel@tonic-gate 				stp->sd_mark = bp;
17940Sstevel@tonic-gate 			(void) putq(q, bp);
17950Sstevel@tonic-gate 
17960Sstevel@tonic-gate 			/*
17970Sstevel@tonic-gate 			 * If message is a PCPROTO message, always use
17980Sstevel@tonic-gate 			 * firstmsgsigs to determine if a signal should be
17990Sstevel@tonic-gate 			 * sent as strrput is the only place to send
18000Sstevel@tonic-gate 			 * signals for PCPROTO. Other messages are based on
18010Sstevel@tonic-gate 			 * the STRGETINPROG flag. The flag determines if
18020Sstevel@tonic-gate 			 * strrput or (k)strgetmsg will be responsible for
18030Sstevel@tonic-gate 			 * sending the signals, in the firstmsgsigs case.
18040Sstevel@tonic-gate 			 */
18050Sstevel@tonic-gate 			if ((hipri_sig == 1) ||
18060Sstevel@tonic-gate 			    (((stp->sd_flag & STRGETINPROG) == 0) &&
18070Sstevel@tonic-gate 			    (q->q_first == bp)))
18080Sstevel@tonic-gate 				signals = (firstmsgsigs | allmsgsigs);
18090Sstevel@tonic-gate 			else
18100Sstevel@tonic-gate 				signals = allmsgsigs;
18110Sstevel@tonic-gate 			break;
18120Sstevel@tonic-gate 
18130Sstevel@tonic-gate 		default:
18140Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
18150Sstevel@tonic-gate 			(void) strrput_nondata(q, bp);
18160Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
18170Sstevel@tonic-gate 			break;
18180Sstevel@tonic-gate 		}
18190Sstevel@tonic-gate 	}
18200Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&stp->sd_lock));
18210Sstevel@tonic-gate 	/*
18220Sstevel@tonic-gate 	 * Wake sleeping read/getmsg and cancel deferred wakeup
18230Sstevel@tonic-gate 	 */
18240Sstevel@tonic-gate 	if (wakeups & RSLEEP)
18250Sstevel@tonic-gate 		stp->sd_wakeq &= ~RSLEEP;
18260Sstevel@tonic-gate 
18270Sstevel@tonic-gate 	wakeups &= stp->sd_flag;
18280Sstevel@tonic-gate 	if (wakeups & RSLEEP) {
18290Sstevel@tonic-gate 		stp->sd_flag &= ~RSLEEP;
18300Sstevel@tonic-gate 		cv_broadcast(&q->q_wait);
18310Sstevel@tonic-gate 	}
18320Sstevel@tonic-gate 	if (wakeups & WSLEEP) {
18330Sstevel@tonic-gate 		stp->sd_flag &= ~WSLEEP;
18340Sstevel@tonic-gate 		cv_broadcast(&_WR(q)->q_wait);
18350Sstevel@tonic-gate 	}
18360Sstevel@tonic-gate 
18370Sstevel@tonic-gate 	if (pollwakeups != 0) {
18380Sstevel@tonic-gate 		if (pollwakeups == (POLLIN | POLLRDNORM)) {
18390Sstevel@tonic-gate 			/*
18400Sstevel@tonic-gate 			 * Can't use rput_opt since it was not
18410Sstevel@tonic-gate 			 * read when sd_lock was held and SR_POLLIN is changed
18420Sstevel@tonic-gate 			 * by strpoll() under sd_lock.
18430Sstevel@tonic-gate 			 */
18440Sstevel@tonic-gate 			if (!(stp->sd_rput_opt & SR_POLLIN))
18450Sstevel@tonic-gate 				goto no_pollwake;
18460Sstevel@tonic-gate 			stp->sd_rput_opt &= ~SR_POLLIN;
18470Sstevel@tonic-gate 		}
18480Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
18490Sstevel@tonic-gate 		pollwakeup(&stp->sd_pollist, pollwakeups);
18500Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
18510Sstevel@tonic-gate 	}
18520Sstevel@tonic-gate no_pollwake:
18530Sstevel@tonic-gate 
18540Sstevel@tonic-gate 	/*
18550Sstevel@tonic-gate 	 * strsendsig can handle multiple signals with a
18560Sstevel@tonic-gate 	 * single call.
18570Sstevel@tonic-gate 	 */
18580Sstevel@tonic-gate 	if (stp->sd_sigflags & signals)
18590Sstevel@tonic-gate 		strsendsig(stp->sd_siglist, signals, band, 0);
18600Sstevel@tonic-gate 	mutex_exit(&stp->sd_lock);
18610Sstevel@tonic-gate 
18620Sstevel@tonic-gate 
18630Sstevel@tonic-gate done:
18640Sstevel@tonic-gate 	if (nextbp == NULL)
18650Sstevel@tonic-gate 		return (0);
18660Sstevel@tonic-gate 
18670Sstevel@tonic-gate 	/*
18680Sstevel@tonic-gate 	 * Any signals were handled the first time.
18690Sstevel@tonic-gate 	 * Wakeups and pollwakeups are redone to avoid any race
18700Sstevel@tonic-gate 	 * conditions - all the messages are not queued until the
18710Sstevel@tonic-gate 	 * last message has been processed by strrput.
18720Sstevel@tonic-gate 	 */
18730Sstevel@tonic-gate 	bp = nextbp;
18740Sstevel@tonic-gate 	signals = firstmsgsigs = allmsgsigs = 0;
18750Sstevel@tonic-gate 	mutex_enter(&stp->sd_lock);
18760Sstevel@tonic-gate 	goto one_more;
18770Sstevel@tonic-gate }
18780Sstevel@tonic-gate 
18790Sstevel@tonic-gate static void
log_dupioc(queue_t * rq,mblk_t * bp)18800Sstevel@tonic-gate log_dupioc(queue_t *rq, mblk_t *bp)
18810Sstevel@tonic-gate {
18820Sstevel@tonic-gate 	queue_t *wq, *qp;
18830Sstevel@tonic-gate 	char *modnames, *mnp, *dname;
18840Sstevel@tonic-gate 	size_t maxmodstr;
18850Sstevel@tonic-gate 	boolean_t islast;
18860Sstevel@tonic-gate 
18870Sstevel@tonic-gate 	/*
18880Sstevel@tonic-gate 	 * Allocate a buffer large enough to hold the names of nstrpush modules
18890Sstevel@tonic-gate 	 * and one driver, with spaces between and NUL terminator.  If we can't
18900Sstevel@tonic-gate 	 * get memory, then we'll just log the driver name.
18910Sstevel@tonic-gate 	 */
18920Sstevel@tonic-gate 	maxmodstr = nstrpush * (FMNAMESZ + 1);
18930Sstevel@tonic-gate 	mnp = modnames = kmem_alloc(maxmodstr, KM_NOSLEEP);
18940Sstevel@tonic-gate 
18950Sstevel@tonic-gate 	/* march down write side to print log message down to the driver */
18960Sstevel@tonic-gate 	wq = WR(rq);
18970Sstevel@tonic-gate 
18980Sstevel@tonic-gate 	/* make sure q_next doesn't shift around while we're grabbing data */
18990Sstevel@tonic-gate 	claimstr(wq);
19000Sstevel@tonic-gate 	qp = wq->q_next;
19010Sstevel@tonic-gate 	do {
19028752SPeter.Memishian@Sun.COM 		dname = Q2NAME(qp);
19030Sstevel@tonic-gate 		islast = !SAMESTR(qp) || qp->q_next == NULL;
19040Sstevel@tonic-gate 		if (modnames == NULL) {
19050Sstevel@tonic-gate 			/*
19060Sstevel@tonic-gate 			 * If we don't have memory, then get the driver name in
19070Sstevel@tonic-gate 			 * the log where we can see it.  Note that memory
19080Sstevel@tonic-gate 			 * pressure is a possible cause of these sorts of bugs.
19090Sstevel@tonic-gate 			 */
19100Sstevel@tonic-gate 			if (islast) {
19110Sstevel@tonic-gate 				modnames = dname;
19120Sstevel@tonic-gate 				maxmodstr = 0;
19130Sstevel@tonic-gate 			}
19140Sstevel@tonic-gate 		} else {
19150Sstevel@tonic-gate 			mnp += snprintf(mnp, FMNAMESZ + 1, "%s", dname);
19160Sstevel@tonic-gate 			if (!islast)
19170Sstevel@tonic-gate 				*mnp++ = ' ';
19180Sstevel@tonic-gate 		}
19190Sstevel@tonic-gate 		qp = qp->q_next;
19200Sstevel@tonic-gate 	} while (!islast);
19210Sstevel@tonic-gate 	releasestr(wq);
19220Sstevel@tonic-gate 	/* Cannot happen unless stream head is corrupt. */
19230Sstevel@tonic-gate 	ASSERT(modnames != NULL);
19240Sstevel@tonic-gate 	(void) strlog(rq->q_qinfo->qi_minfo->mi_idnum, 0, 1,
19250Sstevel@tonic-gate 	    SL_CONSOLE|SL_TRACE|SL_ERROR,
19260Sstevel@tonic-gate 	    "Warning: stream %p received duplicate %X M_IOC%s; module list: %s",
19270Sstevel@tonic-gate 	    rq->q_ptr, ((struct iocblk *)bp->b_rptr)->ioc_cmd,
19280Sstevel@tonic-gate 	    (DB_TYPE(bp) == M_IOCACK ? "ACK" : "NAK"), modnames);
19290Sstevel@tonic-gate 	if (maxmodstr != 0)
19300Sstevel@tonic-gate 		kmem_free(modnames, maxmodstr);
19310Sstevel@tonic-gate }
19320Sstevel@tonic-gate 
19330Sstevel@tonic-gate int
strrput_nondata(queue_t * q,mblk_t * bp)19340Sstevel@tonic-gate strrput_nondata(queue_t *q, mblk_t *bp)
19350Sstevel@tonic-gate {
19360Sstevel@tonic-gate 	struct stdata *stp;
19370Sstevel@tonic-gate 	struct iocblk *iocbp;
19380Sstevel@tonic-gate 	struct stroptions *sop;
19390Sstevel@tonic-gate 	struct copyreq *reqp;
19400Sstevel@tonic-gate 	struct copyresp *resp;
19410Sstevel@tonic-gate 	unsigned char bpri;
19420Sstevel@tonic-gate 	unsigned char  flushed_already = 0;
19430Sstevel@tonic-gate 
19440Sstevel@tonic-gate 	stp = (struct stdata *)q->q_ptr;
19450Sstevel@tonic-gate 
19460Sstevel@tonic-gate 	ASSERT(!(stp->sd_flag & STPLEX));
19470Sstevel@tonic-gate 	ASSERT(qclaimed(q));
19480Sstevel@tonic-gate 
19490Sstevel@tonic-gate 	switch (bp->b_datap->db_type) {
19500Sstevel@tonic-gate 	case M_ERROR:
19510Sstevel@tonic-gate 		/*
19520Sstevel@tonic-gate 		 * An error has occurred downstream, the errno is in the first
19530Sstevel@tonic-gate 		 * bytes of the message.
19540Sstevel@tonic-gate 		 */
19550Sstevel@tonic-gate 		if ((bp->b_wptr - bp->b_rptr) == 2) {	/* New flavor */
19560Sstevel@tonic-gate 			unsigned char rw = 0;
19570Sstevel@tonic-gate 
19580Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
19590Sstevel@tonic-gate 			if (*bp->b_rptr != NOERROR) {	/* read error */
19600Sstevel@tonic-gate 				if (*bp->b_rptr != 0) {
19610Sstevel@tonic-gate 					if (stp->sd_flag & STRDERR)
19620Sstevel@tonic-gate 						flushed_already |= FLUSHR;
19630Sstevel@tonic-gate 					stp->sd_flag |= STRDERR;
19640Sstevel@tonic-gate 					rw |= FLUSHR;
19650Sstevel@tonic-gate 				} else {
19660Sstevel@tonic-gate 					stp->sd_flag &= ~STRDERR;
19670Sstevel@tonic-gate 				}
19680Sstevel@tonic-gate 				stp->sd_rerror = *bp->b_rptr;
19690Sstevel@tonic-gate 			}
19700Sstevel@tonic-gate 			bp->b_rptr++;
19710Sstevel@tonic-gate 			if (*bp->b_rptr != NOERROR) {	/* write error */
19720Sstevel@tonic-gate 				if (*bp->b_rptr != 0) {
19730Sstevel@tonic-gate 					if (stp->sd_flag & STWRERR)
19740Sstevel@tonic-gate 						flushed_already |= FLUSHW;
19750Sstevel@tonic-gate 					stp->sd_flag |= STWRERR;
19760Sstevel@tonic-gate 					rw |= FLUSHW;
19770Sstevel@tonic-gate 				} else {
19780Sstevel@tonic-gate 					stp->sd_flag &= ~STWRERR;
19790Sstevel@tonic-gate 				}
19800Sstevel@tonic-gate 				stp->sd_werror = *bp->b_rptr;
19810Sstevel@tonic-gate 			}
19820Sstevel@tonic-gate 			if (rw) {
19830Sstevel@tonic-gate 				TRACE_2(TR_FAC_STREAMS_FR, TR_STRRPUT_WAKE,
19845753Sgww 				    "strrput cv_broadcast:q %p, bp %p",
19855753Sgww 				    q, bp);
19860Sstevel@tonic-gate 				cv_broadcast(&q->q_wait); /* readers */
19870Sstevel@tonic-gate 				cv_broadcast(&_WR(q)->q_wait); /* writers */
19880Sstevel@tonic-gate 				cv_broadcast(&stp->sd_monitor); /* ioctllers */
19890Sstevel@tonic-gate 
19900Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
19910Sstevel@tonic-gate 				pollwakeup(&stp->sd_pollist, POLLERR);
19920Sstevel@tonic-gate 				mutex_enter(&stp->sd_lock);
19930Sstevel@tonic-gate 
19940Sstevel@tonic-gate 				if (stp->sd_sigflags & S_ERROR)
19950Sstevel@tonic-gate 					strsendsig(stp->sd_siglist, S_ERROR, 0,
19960Sstevel@tonic-gate 					    ((rw & FLUSHR) ? stp->sd_rerror :
19970Sstevel@tonic-gate 					    stp->sd_werror));
19980Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
19990Sstevel@tonic-gate 				/*
20000Sstevel@tonic-gate 				 * Send the M_FLUSH only
20010Sstevel@tonic-gate 				 * for the first M_ERROR
20020Sstevel@tonic-gate 				 * message on the stream
20030Sstevel@tonic-gate 				 */
20040Sstevel@tonic-gate 				if (flushed_already == rw) {
20050Sstevel@tonic-gate 					freemsg(bp);
20060Sstevel@tonic-gate 					return (0);
20070Sstevel@tonic-gate 				}
20080Sstevel@tonic-gate 
20090Sstevel@tonic-gate 				bp->b_datap->db_type = M_FLUSH;
20100Sstevel@tonic-gate 				*bp->b_rptr = rw;
20110Sstevel@tonic-gate 				bp->b_wptr = bp->b_rptr + 1;
20120Sstevel@tonic-gate 				/*
20130Sstevel@tonic-gate 				 * Protect against the driver
20140Sstevel@tonic-gate 				 * passing up messages after
20150Sstevel@tonic-gate 				 * it has done a qprocsoff
20160Sstevel@tonic-gate 				 */
20170Sstevel@tonic-gate 				if (_OTHERQ(q)->q_next == NULL)
20180Sstevel@tonic-gate 					freemsg(bp);
20190Sstevel@tonic-gate 				else
20200Sstevel@tonic-gate 					qreply(q, bp);
20210Sstevel@tonic-gate 				return (0);
20220Sstevel@tonic-gate 			} else
20230Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
20240Sstevel@tonic-gate 		} else if (*bp->b_rptr != 0) {		/* Old flavor */
20250Sstevel@tonic-gate 				if (stp->sd_flag & (STRDERR|STWRERR))
20260Sstevel@tonic-gate 					flushed_already = FLUSHRW;
20270Sstevel@tonic-gate 				mutex_enter(&stp->sd_lock);
20280Sstevel@tonic-gate 				stp->sd_flag |= (STRDERR|STWRERR);
20290Sstevel@tonic-gate 				stp->sd_rerror = *bp->b_rptr;
20300Sstevel@tonic-gate 				stp->sd_werror = *bp->b_rptr;
20310Sstevel@tonic-gate 				TRACE_2(TR_FAC_STREAMS_FR,
20325753Sgww 				    TR_STRRPUT_WAKE2,
20335753Sgww 				    "strrput wakeup #2:q %p, bp %p", q, bp);
20340Sstevel@tonic-gate 				cv_broadcast(&q->q_wait); /* the readers */
20350Sstevel@tonic-gate 				cv_broadcast(&_WR(q)->q_wait); /* the writers */
20360Sstevel@tonic-gate 				cv_broadcast(&stp->sd_monitor); /* ioctllers */
20370Sstevel@tonic-gate 
20380Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
20390Sstevel@tonic-gate 				pollwakeup(&stp->sd_pollist, POLLERR);
20400Sstevel@tonic-gate 				mutex_enter(&stp->sd_lock);
20410Sstevel@tonic-gate 
20420Sstevel@tonic-gate 				if (stp->sd_sigflags & S_ERROR)
20430Sstevel@tonic-gate 					strsendsig(stp->sd_siglist, S_ERROR, 0,
20440Sstevel@tonic-gate 					    (stp->sd_werror ? stp->sd_werror :
20450Sstevel@tonic-gate 					    stp->sd_rerror));
20460Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
20470Sstevel@tonic-gate 
20480Sstevel@tonic-gate 				/*
20490Sstevel@tonic-gate 				 * Send the M_FLUSH only
20500Sstevel@tonic-gate 				 * for the first M_ERROR
20510Sstevel@tonic-gate 				 * message on the stream
20520Sstevel@tonic-gate 				 */
20530Sstevel@tonic-gate 				if (flushed_already != FLUSHRW) {
20540Sstevel@tonic-gate 					bp->b_datap->db_type = M_FLUSH;
20550Sstevel@tonic-gate 					*bp->b_rptr = FLUSHRW;
20560Sstevel@tonic-gate 					/*
20570Sstevel@tonic-gate 					 * Protect against the driver passing up
20580Sstevel@tonic-gate 					 * messages after it has done a
20590Sstevel@tonic-gate 					 * qprocsoff.
20600Sstevel@tonic-gate 					 */
20610Sstevel@tonic-gate 				if (_OTHERQ(q)->q_next == NULL)
20620Sstevel@tonic-gate 					freemsg(bp);
20630Sstevel@tonic-gate 				else
20640Sstevel@tonic-gate 					qreply(q, bp);
20650Sstevel@tonic-gate 				return (0);
20660Sstevel@tonic-gate 				}
20670Sstevel@tonic-gate 		}
20680Sstevel@tonic-gate 		freemsg(bp);
20690Sstevel@tonic-gate 		return (0);
20700Sstevel@tonic-gate 
20710Sstevel@tonic-gate 	case M_HANGUP:
20720Sstevel@tonic-gate 
20730Sstevel@tonic-gate 		freemsg(bp);
20740Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
20750Sstevel@tonic-gate 		stp->sd_werror = ENXIO;
20760Sstevel@tonic-gate 		stp->sd_flag |= STRHUP;
20770Sstevel@tonic-gate 		stp->sd_flag &= ~(WSLEEP|RSLEEP);
20780Sstevel@tonic-gate 
20790Sstevel@tonic-gate 		/*
20800Sstevel@tonic-gate 		 * send signal if controlling tty
20810Sstevel@tonic-gate 		 */
20820Sstevel@tonic-gate 
20830Sstevel@tonic-gate 		if (stp->sd_sidp) {
20840Sstevel@tonic-gate 			prsignal(stp->sd_sidp, SIGHUP);
20850Sstevel@tonic-gate 			if (stp->sd_sidp != stp->sd_pgidp)
20860Sstevel@tonic-gate 				pgsignal(stp->sd_pgidp, SIGTSTP);
20870Sstevel@tonic-gate 		}
20880Sstevel@tonic-gate 
20890Sstevel@tonic-gate 		/*
20900Sstevel@tonic-gate 		 * wake up read, write, and exception pollers and
20910Sstevel@tonic-gate 		 * reset wakeup mechanism.
20920Sstevel@tonic-gate 		 */
20930Sstevel@tonic-gate 		cv_broadcast(&q->q_wait);	/* the readers */
20940Sstevel@tonic-gate 		cv_broadcast(&_WR(q)->q_wait);	/* the writers */
20950Sstevel@tonic-gate 		cv_broadcast(&stp->sd_monitor);	/* the ioctllers */
20962712Snn35248 		strhup(stp);
20970Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
20980Sstevel@tonic-gate 		return (0);
20990Sstevel@tonic-gate 
21000Sstevel@tonic-gate 	case M_UNHANGUP:
21010Sstevel@tonic-gate 		freemsg(bp);
21020Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
21030Sstevel@tonic-gate 		stp->sd_werror = 0;
21040Sstevel@tonic-gate 		stp->sd_flag &= ~STRHUP;
21050Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
21060Sstevel@tonic-gate 		return (0);
21070Sstevel@tonic-gate 
21080Sstevel@tonic-gate 	case M_SIG:
21090Sstevel@tonic-gate 		/*
21100Sstevel@tonic-gate 		 * Someone downstream wants to post a signal.  The
21110Sstevel@tonic-gate 		 * signal to post is contained in the first byte of the
21120Sstevel@tonic-gate 		 * message.  If the message would go on the front of
21130Sstevel@tonic-gate 		 * the queue, send a signal to the process group
21140Sstevel@tonic-gate 		 * (if not SIGPOLL) or to the siglist processes
21150Sstevel@tonic-gate 		 * (SIGPOLL).  If something is already on the queue,
21160Sstevel@tonic-gate 		 * OR if we are delivering a delayed suspend (*sigh*
21170Sstevel@tonic-gate 		 * another "tty" hack) and there's no one sleeping already,
21180Sstevel@tonic-gate 		 * just enqueue the message.
21190Sstevel@tonic-gate 		 */
21200Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
21210Sstevel@tonic-gate 		if (q->q_first || (*bp->b_rptr == SIGTSTP &&
21220Sstevel@tonic-gate 		    !(stp->sd_flag & RSLEEP))) {
21230Sstevel@tonic-gate 			(void) putq(q, bp);
21240Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
21250Sstevel@tonic-gate 			return (0);
21260Sstevel@tonic-gate 		}
21270Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
21280Sstevel@tonic-gate 		/* FALLTHRU */
21290Sstevel@tonic-gate 
21300Sstevel@tonic-gate 	case M_PCSIG:
21310Sstevel@tonic-gate 		/*
21320Sstevel@tonic-gate 		 * Don't enqueue, just post the signal.
21330Sstevel@tonic-gate 		 */
21340Sstevel@tonic-gate 		strsignal(stp, *bp->b_rptr, 0L);
21350Sstevel@tonic-gate 		freemsg(bp);
21360Sstevel@tonic-gate 		return (0);
21370Sstevel@tonic-gate 
21386583Smeem 	case M_CMD:
21396583Smeem 		if (MBLKL(bp) != sizeof (cmdblk_t)) {
21406583Smeem 			freemsg(bp);
21416583Smeem 			return (0);
21426583Smeem 		}
21436583Smeem 
21446583Smeem 		mutex_enter(&stp->sd_lock);
21456583Smeem 		if (stp->sd_flag & STRCMDWAIT) {
21466583Smeem 			ASSERT(stp->sd_cmdblk == NULL);
21476583Smeem 			stp->sd_cmdblk = bp;
21486583Smeem 			cv_broadcast(&stp->sd_monitor);
21496583Smeem 			mutex_exit(&stp->sd_lock);
21506583Smeem 		} else {
21516583Smeem 			mutex_exit(&stp->sd_lock);
21526583Smeem 			freemsg(bp);
21536583Smeem 		}
21546583Smeem 		return (0);
21556583Smeem 
21560Sstevel@tonic-gate 	case M_FLUSH:
21570Sstevel@tonic-gate 		/*
21580Sstevel@tonic-gate 		 * Flush queues.  The indication of which queues to flush
21590Sstevel@tonic-gate 		 * is in the first byte of the message.  If the read queue
21600Sstevel@tonic-gate 		 * is specified, then flush it.  If FLUSHBAND is set, just
21610Sstevel@tonic-gate 		 * flush the band specified by the second byte of the message.
21620Sstevel@tonic-gate 		 *
21630Sstevel@tonic-gate 		 * If a module has issued a M_SETOPT to not flush hi
21640Sstevel@tonic-gate 		 * priority messages off of the stream head, then pass this
21650Sstevel@tonic-gate 		 * flag into the flushq code to preserve such messages.
21660Sstevel@tonic-gate 		 */
21670Sstevel@tonic-gate 
21680Sstevel@tonic-gate 		if (*bp->b_rptr & FLUSHR) {
21690Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
21700Sstevel@tonic-gate 			if (*bp->b_rptr & FLUSHBAND) {
21710Sstevel@tonic-gate 				ASSERT((bp->b_wptr - bp->b_rptr) >= 2);
21720Sstevel@tonic-gate 				flushband(q, *(bp->b_rptr + 1), FLUSHALL);
21730Sstevel@tonic-gate 			} else
21740Sstevel@tonic-gate 				flushq_common(q, FLUSHALL,
21750Sstevel@tonic-gate 				    stp->sd_read_opt & RFLUSHPCPROT);
21760Sstevel@tonic-gate 			if ((q->q_first == NULL) ||
21770Sstevel@tonic-gate 			    (q->q_first->b_datap->db_type < QPCTL))
21780Sstevel@tonic-gate 				stp->sd_flag &= ~STRPRI;
21790Sstevel@tonic-gate 			else {
21800Sstevel@tonic-gate 				ASSERT(stp->sd_flag & STRPRI);
21810Sstevel@tonic-gate 			}
21820Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
21830Sstevel@tonic-gate 		}
21840Sstevel@tonic-gate 		if ((*bp->b_rptr & FLUSHW) && !(bp->b_flag & MSGNOLOOP)) {
21850Sstevel@tonic-gate 			*bp->b_rptr &= ~FLUSHR;
21860Sstevel@tonic-gate 			bp->b_flag |= MSGNOLOOP;
21870Sstevel@tonic-gate 			/*
21880Sstevel@tonic-gate 			 * Protect against the driver passing up
21890Sstevel@tonic-gate 			 * messages after it has done a qprocsoff.
21900Sstevel@tonic-gate 			 */
21910Sstevel@tonic-gate 			if (_OTHERQ(q)->q_next == NULL)
21920Sstevel@tonic-gate 				freemsg(bp);
21930Sstevel@tonic-gate 			else
21940Sstevel@tonic-gate 				qreply(q, bp);
21950Sstevel@tonic-gate 			return (0);
21960Sstevel@tonic-gate 		}
21970Sstevel@tonic-gate 		freemsg(bp);
21980Sstevel@tonic-gate 		return (0);
21990Sstevel@tonic-gate 
22000Sstevel@tonic-gate 	case M_IOCACK:
22010Sstevel@tonic-gate 	case M_IOCNAK:
22020Sstevel@tonic-gate 		iocbp = (struct iocblk *)bp->b_rptr;
22030Sstevel@tonic-gate 		/*
22040Sstevel@tonic-gate 		 * If not waiting for ACK or NAK then just free msg.
22050Sstevel@tonic-gate 		 * If incorrect id sequence number then just free msg.
22060Sstevel@tonic-gate 		 * If already have ACK or NAK for user then this is a
22070Sstevel@tonic-gate 		 *    duplicate, display a warning and free the msg.
22080Sstevel@tonic-gate 		 */
22090Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
22100Sstevel@tonic-gate 		if ((stp->sd_flag & IOCWAIT) == 0 || stp->sd_iocblk ||
22110Sstevel@tonic-gate 		    (stp->sd_iocid != iocbp->ioc_id)) {
22120Sstevel@tonic-gate 			/*
22130Sstevel@tonic-gate 			 * If the ACK/NAK is a dup, display a message
22140Sstevel@tonic-gate 			 * Dup is when sd_iocid == ioc_id, and
22150Sstevel@tonic-gate 			 * sd_iocblk == <valid ptr> or -1 (the former
22160Sstevel@tonic-gate 			 * is when an ioctl has been put on the stream
22170Sstevel@tonic-gate 			 * head, but has not yet been consumed, the
22180Sstevel@tonic-gate 			 * later is when it has been consumed).
22190Sstevel@tonic-gate 			 */
22200Sstevel@tonic-gate 			if ((stp->sd_iocid == iocbp->ioc_id) &&
22210Sstevel@tonic-gate 			    (stp->sd_iocblk != NULL)) {
22220Sstevel@tonic-gate 				log_dupioc(q, bp);
22230Sstevel@tonic-gate 			}
22240Sstevel@tonic-gate 			freemsg(bp);
22250Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
22260Sstevel@tonic-gate 			return (0);
22270Sstevel@tonic-gate 		}
22280Sstevel@tonic-gate 
22290Sstevel@tonic-gate 		/*
22300Sstevel@tonic-gate 		 * Assign ACK or NAK to user and wake up.
22310Sstevel@tonic-gate 		 */
22320Sstevel@tonic-gate 		stp->sd_iocblk = bp;
22330Sstevel@tonic-gate 		cv_broadcast(&stp->sd_monitor);
22340Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
22350Sstevel@tonic-gate 		return (0);
22360Sstevel@tonic-gate 
22370Sstevel@tonic-gate 	case M_COPYIN:
22380Sstevel@tonic-gate 	case M_COPYOUT:
22390Sstevel@tonic-gate 		reqp = (struct copyreq *)bp->b_rptr;
22400Sstevel@tonic-gate 
22410Sstevel@tonic-gate 		/*
22420Sstevel@tonic-gate 		 * If not waiting for ACK or NAK then just fail request.
22430Sstevel@tonic-gate 		 * If already have ACK, NAK, or copy request, then just
22440Sstevel@tonic-gate 		 * fail request.
22450Sstevel@tonic-gate 		 * If incorrect id sequence number then just fail request.
22460Sstevel@tonic-gate 		 */
22470Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
22480Sstevel@tonic-gate 		if ((stp->sd_flag & IOCWAIT) == 0 || stp->sd_iocblk ||
22490Sstevel@tonic-gate 		    (stp->sd_iocid != reqp->cq_id)) {
22500Sstevel@tonic-gate 			if (bp->b_cont) {
22510Sstevel@tonic-gate 				freemsg(bp->b_cont);
22520Sstevel@tonic-gate 				bp->b_cont = NULL;
22530Sstevel@tonic-gate 			}
22540Sstevel@tonic-gate 			bp->b_datap->db_type = M_IOCDATA;
22550Sstevel@tonic-gate 			bp->b_wptr = bp->b_rptr + sizeof (struct copyresp);
22560Sstevel@tonic-gate 			resp = (struct copyresp *)bp->b_rptr;
22570Sstevel@tonic-gate 			resp->cp_rval = (caddr_t)1;	/* failure */
22580Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
22590Sstevel@tonic-gate 			putnext(stp->sd_wrq, bp);
22600Sstevel@tonic-gate 			return (0);
22610Sstevel@tonic-gate 		}
22620Sstevel@tonic-gate 
22630Sstevel@tonic-gate 		/*
22640Sstevel@tonic-gate 		 * Assign copy request to user and wake up.
22650Sstevel@tonic-gate 		 */
22660Sstevel@tonic-gate 		stp->sd_iocblk = bp;
22670Sstevel@tonic-gate 		cv_broadcast(&stp->sd_monitor);
22680Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
22690Sstevel@tonic-gate 		return (0);
22700Sstevel@tonic-gate 
22710Sstevel@tonic-gate 	case M_SETOPTS:
22720Sstevel@tonic-gate 		/*
22730Sstevel@tonic-gate 		 * Set stream head options (read option, write offset,
22740Sstevel@tonic-gate 		 * min/max packet size, and/or high/low water marks for
22750Sstevel@tonic-gate 		 * the read side only).
22760Sstevel@tonic-gate 		 */
22770Sstevel@tonic-gate 
22780Sstevel@tonic-gate 		bpri = 0;
22790Sstevel@tonic-gate 		sop = (struct stroptions *)bp->b_rptr;
22800Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
22810Sstevel@tonic-gate 		if (sop->so_flags & SO_READOPT) {
22820Sstevel@tonic-gate 			switch (sop->so_readopt & RMODEMASK) {
22830Sstevel@tonic-gate 			case RNORM:
22840Sstevel@tonic-gate 				stp->sd_read_opt &= ~(RD_MSGDIS | RD_MSGNODIS);
22850Sstevel@tonic-gate 				break;
22860Sstevel@tonic-gate 
22870Sstevel@tonic-gate 			case RMSGD:
22880Sstevel@tonic-gate 				stp->sd_read_opt =
22890Sstevel@tonic-gate 				    ((stp->sd_read_opt & ~RD_MSGNODIS) |
22900Sstevel@tonic-gate 				    RD_MSGDIS);
22910Sstevel@tonic-gate 				break;
22920Sstevel@tonic-gate 
22930Sstevel@tonic-gate 			case RMSGN:
22940Sstevel@tonic-gate 				stp->sd_read_opt =
22950Sstevel@tonic-gate 				    ((stp->sd_read_opt & ~RD_MSGDIS) |
22960Sstevel@tonic-gate 				    RD_MSGNODIS);
22970Sstevel@tonic-gate 				break;
22980Sstevel@tonic-gate 			}
22990Sstevel@tonic-gate 			switch (sop->so_readopt & RPROTMASK) {
23000Sstevel@tonic-gate 			case RPROTNORM:
23010Sstevel@tonic-gate 				stp->sd_read_opt &= ~(RD_PROTDAT | RD_PROTDIS);
23020Sstevel@tonic-gate 				break;
23030Sstevel@tonic-gate 
23040Sstevel@tonic-gate 			case RPROTDAT:
23050Sstevel@tonic-gate 				stp->sd_read_opt =
23060Sstevel@tonic-gate 				    ((stp->sd_read_opt & ~RD_PROTDIS) |
23070Sstevel@tonic-gate 				    RD_PROTDAT);
23080Sstevel@tonic-gate 				break;
23090Sstevel@tonic-gate 
23100Sstevel@tonic-gate 			case RPROTDIS:
23110Sstevel@tonic-gate 				stp->sd_read_opt =
23120Sstevel@tonic-gate 				    ((stp->sd_read_opt & ~RD_PROTDAT) |
23130Sstevel@tonic-gate 				    RD_PROTDIS);
23140Sstevel@tonic-gate 				break;
23150Sstevel@tonic-gate 			}
23160Sstevel@tonic-gate 			switch (sop->so_readopt & RFLUSHMASK) {
23170Sstevel@tonic-gate 			case RFLUSHPCPROT:
23180Sstevel@tonic-gate 				/*
23190Sstevel@tonic-gate 				 * This sets the stream head to NOT flush
23200Sstevel@tonic-gate 				 * M_PCPROTO messages.
23210Sstevel@tonic-gate 				 */
23220Sstevel@tonic-gate 				stp->sd_read_opt |= RFLUSHPCPROT;
23230Sstevel@tonic-gate 				break;
23240Sstevel@tonic-gate 			}
23250Sstevel@tonic-gate 		}
23260Sstevel@tonic-gate 		if (sop->so_flags & SO_ERROPT) {
23270Sstevel@tonic-gate 			switch (sop->so_erropt & RERRMASK) {
23280Sstevel@tonic-gate 			case RERRNORM:
23290Sstevel@tonic-gate 				stp->sd_flag &= ~STRDERRNONPERSIST;
23300Sstevel@tonic-gate 				break;
23310Sstevel@tonic-gate 			case RERRNONPERSIST:
23320Sstevel@tonic-gate 				stp->sd_flag |= STRDERRNONPERSIST;
23330Sstevel@tonic-gate 				break;
23340Sstevel@tonic-gate 			}
23350Sstevel@tonic-gate 			switch (sop->so_erropt & WERRMASK) {
23360Sstevel@tonic-gate 			case WERRNORM:
23370Sstevel@tonic-gate 				stp->sd_flag &= ~STWRERRNONPERSIST;
23380Sstevel@tonic-gate 				break;
23390Sstevel@tonic-gate 			case WERRNONPERSIST:
23400Sstevel@tonic-gate 				stp->sd_flag |= STWRERRNONPERSIST;
23410Sstevel@tonic-gate 				break;
23420Sstevel@tonic-gate 			}
23430Sstevel@tonic-gate 		}
23440Sstevel@tonic-gate 		if (sop->so_flags & SO_COPYOPT) {
23450Sstevel@tonic-gate 			if (sop->so_copyopt & ZCVMSAFE) {
23460Sstevel@tonic-gate 				stp->sd_copyflag |= STZCVMSAFE;
23470Sstevel@tonic-gate 				stp->sd_copyflag &= ~STZCVMUNSAFE;
23480Sstevel@tonic-gate 			} else if (sop->so_copyopt & ZCVMUNSAFE) {
23490Sstevel@tonic-gate 				stp->sd_copyflag |= STZCVMUNSAFE;
23500Sstevel@tonic-gate 				stp->sd_copyflag &= ~STZCVMSAFE;
23510Sstevel@tonic-gate 			}
23520Sstevel@tonic-gate 
23530Sstevel@tonic-gate 			if (sop->so_copyopt & COPYCACHED) {
23540Sstevel@tonic-gate 				stp->sd_copyflag |= STRCOPYCACHED;
23550Sstevel@tonic-gate 			}
23560Sstevel@tonic-gate 		}
23570Sstevel@tonic-gate 		if (sop->so_flags & SO_WROFF)
23580Sstevel@tonic-gate 			stp->sd_wroff = sop->so_wroff;
2359898Skais 		if (sop->so_flags & SO_TAIL)
2360898Skais 			stp->sd_tail = sop->so_tail;
23610Sstevel@tonic-gate 		if (sop->so_flags & SO_MINPSZ)
23620Sstevel@tonic-gate 			q->q_minpsz = sop->so_minpsz;
23630Sstevel@tonic-gate 		if (sop->so_flags & SO_MAXPSZ)
23640Sstevel@tonic-gate 			q->q_maxpsz = sop->so_maxpsz;
23650Sstevel@tonic-gate 		if (sop->so_flags & SO_MAXBLK)
23660Sstevel@tonic-gate 			stp->sd_maxblk = sop->so_maxblk;
23670Sstevel@tonic-gate 		if (sop->so_flags & SO_HIWAT) {
23685753Sgww 			if (sop->so_flags & SO_BAND) {
23695753Sgww 				if (strqset(q, QHIWAT,
23705753Sgww 				    sop->so_band, sop->so_hiwat)) {
23715753Sgww 					cmn_err(CE_WARN, "strrput: could not "
23725753Sgww 					    "allocate qband\n");
23735753Sgww 				} else {
23745753Sgww 					bpri = sop->so_band;
23755753Sgww 				}
23765753Sgww 			} else {
23775753Sgww 				q->q_hiwat = sop->so_hiwat;
23785753Sgww 			}
23790Sstevel@tonic-gate 		}
23800Sstevel@tonic-gate 		if (sop->so_flags & SO_LOWAT) {
23815753Sgww 			if (sop->so_flags & SO_BAND) {
23825753Sgww 				if (strqset(q, QLOWAT,
23835753Sgww 				    sop->so_band, sop->so_lowat)) {
23845753Sgww 					cmn_err(CE_WARN, "strrput: could not "
23855753Sgww 					    "allocate qband\n");
23865753Sgww 				} else {
23875753Sgww 					bpri = sop->so_band;
23885753Sgww 				}
23895753Sgww 			} else {
23905753Sgww 				q->q_lowat = sop->so_lowat;
23915753Sgww 			}
23920Sstevel@tonic-gate 		}
23930Sstevel@tonic-gate 		if (sop->so_flags & SO_MREADON)
23940Sstevel@tonic-gate 			stp->sd_flag |= SNDMREAD;
23950Sstevel@tonic-gate 		if (sop->so_flags & SO_MREADOFF)
23960Sstevel@tonic-gate 			stp->sd_flag &= ~SNDMREAD;
23970Sstevel@tonic-gate 		if (sop->so_flags & SO_NDELON)
23980Sstevel@tonic-gate 			stp->sd_flag |= OLDNDELAY;
23990Sstevel@tonic-gate 		if (sop->so_flags & SO_NDELOFF)
24000Sstevel@tonic-gate 			stp->sd_flag &= ~OLDNDELAY;
24010Sstevel@tonic-gate 		if (sop->so_flags & SO_ISTTY)
24020Sstevel@tonic-gate 			stp->sd_flag |= STRISTTY;
24030Sstevel@tonic-gate 		if (sop->so_flags & SO_ISNTTY)
24040Sstevel@tonic-gate 			stp->sd_flag &= ~STRISTTY;
24050Sstevel@tonic-gate 		if (sop->so_flags & SO_TOSTOP)
24060Sstevel@tonic-gate 			stp->sd_flag |= STRTOSTOP;
24070Sstevel@tonic-gate 		if (sop->so_flags & SO_TONSTOP)
24080Sstevel@tonic-gate 			stp->sd_flag &= ~STRTOSTOP;
24090Sstevel@tonic-gate 		if (sop->so_flags & SO_DELIM)
24100Sstevel@tonic-gate 			stp->sd_flag |= STRDELIM;
24110Sstevel@tonic-gate 		if (sop->so_flags & SO_NODELIM)
24120Sstevel@tonic-gate 			stp->sd_flag &= ~STRDELIM;
24130Sstevel@tonic-gate 
24140Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
24150Sstevel@tonic-gate 		freemsg(bp);
24160Sstevel@tonic-gate 
24170Sstevel@tonic-gate 		/* Check backenable in case the water marks changed */
24180Sstevel@tonic-gate 		qbackenable(q, bpri);
24190Sstevel@tonic-gate 		return (0);
24200Sstevel@tonic-gate 
24210Sstevel@tonic-gate 	/*
24220Sstevel@tonic-gate 	 * The following set of cases deal with situations where two stream
24230Sstevel@tonic-gate 	 * heads are connected to each other (twisted streams).  These messages
24240Sstevel@tonic-gate 	 * have no meaning at the stream head.
24250Sstevel@tonic-gate 	 */
24260Sstevel@tonic-gate 	case M_BREAK:
24270Sstevel@tonic-gate 	case M_CTL:
24280Sstevel@tonic-gate 	case M_DELAY:
24290Sstevel@tonic-gate 	case M_START:
24300Sstevel@tonic-gate 	case M_STOP:
24310Sstevel@tonic-gate 	case M_IOCDATA:
24320Sstevel@tonic-gate 	case M_STARTI:
24330Sstevel@tonic-gate 	case M_STOPI:
24340Sstevel@tonic-gate 		freemsg(bp);
24350Sstevel@tonic-gate 		return (0);
24360Sstevel@tonic-gate 
24370Sstevel@tonic-gate 	case M_IOCTL:
24380Sstevel@tonic-gate 		/*
24390Sstevel@tonic-gate 		 * Always NAK this condition
24400Sstevel@tonic-gate 		 * (makes no sense)
24410Sstevel@tonic-gate 		 * If there is one or more threads in the read side
24420Sstevel@tonic-gate 		 * rwnext we have to defer the nacking until that thread
24430Sstevel@tonic-gate 		 * returns (in strget).
24440Sstevel@tonic-gate 		 */
24450Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
24460Sstevel@tonic-gate 		if (stp->sd_struiodnak != 0) {
24470Sstevel@tonic-gate 			/*
24480Sstevel@tonic-gate 			 * Defer NAK to the streamhead. Queue at the end
24490Sstevel@tonic-gate 			 * the list.
24500Sstevel@tonic-gate 			 */
24510Sstevel@tonic-gate 			mblk_t *mp = stp->sd_struionak;
24520Sstevel@tonic-gate 
24530Sstevel@tonic-gate 			while (mp && mp->b_next)
24540Sstevel@tonic-gate 				mp = mp->b_next;
24550Sstevel@tonic-gate 			if (mp)
24560Sstevel@tonic-gate 				mp->b_next = bp;
24570Sstevel@tonic-gate 			else
24580Sstevel@tonic-gate 				stp->sd_struionak = bp;
24590Sstevel@tonic-gate 			bp->b_next = NULL;
24600Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
24610Sstevel@tonic-gate 			return (0);
24620Sstevel@tonic-gate 		}
24630Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
24640Sstevel@tonic-gate 
24650Sstevel@tonic-gate 		bp->b_datap->db_type = M_IOCNAK;
24660Sstevel@tonic-gate 		/*
24670Sstevel@tonic-gate 		 * Protect against the driver passing up
24680Sstevel@tonic-gate 		 * messages after it has done a qprocsoff.
24690Sstevel@tonic-gate 		 */
24700Sstevel@tonic-gate 		if (_OTHERQ(q)->q_next == NULL)
24710Sstevel@tonic-gate 			freemsg(bp);
24720Sstevel@tonic-gate 		else
24730Sstevel@tonic-gate 			qreply(q, bp);
24740Sstevel@tonic-gate 		return (0);
24750Sstevel@tonic-gate 
24760Sstevel@tonic-gate 	default:
24770Sstevel@tonic-gate #ifdef DEBUG
24780Sstevel@tonic-gate 		cmn_err(CE_WARN,
24795753Sgww 		    "bad message type %x received at stream head\n",
24805753Sgww 		    bp->b_datap->db_type);
24810Sstevel@tonic-gate #endif
24820Sstevel@tonic-gate 		freemsg(bp);
24830Sstevel@tonic-gate 		return (0);
24840Sstevel@tonic-gate 	}
24850Sstevel@tonic-gate 
24860Sstevel@tonic-gate 	/* NOTREACHED */
24870Sstevel@tonic-gate }
24880Sstevel@tonic-gate 
24890Sstevel@tonic-gate /*
24900Sstevel@tonic-gate  * Check if the stream pointed to by `stp' can be written to, and return an
24910Sstevel@tonic-gate  * error code if not.  If `eiohup' is set, then return EIO if STRHUP is set.
24920Sstevel@tonic-gate  * If `sigpipeok' is set and the SW_SIGPIPE option is enabled on the stream,
24930Sstevel@tonic-gate  * then always return EPIPE and send a SIGPIPE to the invoking thread.
24940Sstevel@tonic-gate  */
24950Sstevel@tonic-gate static int
strwriteable(struct stdata * stp,boolean_t eiohup,boolean_t sigpipeok)24960Sstevel@tonic-gate strwriteable(struct stdata *stp, boolean_t eiohup, boolean_t sigpipeok)
24970Sstevel@tonic-gate {
24980Sstevel@tonic-gate 	int error;
24990Sstevel@tonic-gate 
25000Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&stp->sd_lock));
25010Sstevel@tonic-gate 
25020Sstevel@tonic-gate 	/*
25030Sstevel@tonic-gate 	 * For modem support, POSIX states that on writes, EIO should
25040Sstevel@tonic-gate 	 * be returned if the stream has been hung up.
25050Sstevel@tonic-gate 	 */
25060Sstevel@tonic-gate 	if (eiohup && (stp->sd_flag & (STPLEX|STRHUP)) == STRHUP)
25070Sstevel@tonic-gate 		error = EIO;
25080Sstevel@tonic-gate 	else
25090Sstevel@tonic-gate 		error = strgeterr(stp, STRHUP|STPLEX|STWRERR, 0);
25100Sstevel@tonic-gate 
25110Sstevel@tonic-gate 	if (error != 0) {
25120Sstevel@tonic-gate 		if (!(stp->sd_flag & STPLEX) &&
25130Sstevel@tonic-gate 		    (stp->sd_wput_opt & SW_SIGPIPE) && sigpipeok) {
25140Sstevel@tonic-gate 			tsignal(curthread, SIGPIPE);
25150Sstevel@tonic-gate 			error = EPIPE;
25160Sstevel@tonic-gate 		}
25170Sstevel@tonic-gate 	}
25180Sstevel@tonic-gate 
25190Sstevel@tonic-gate 	return (error);
25200Sstevel@tonic-gate }
25210Sstevel@tonic-gate 
25220Sstevel@tonic-gate /*
25230Sstevel@tonic-gate  * Copyin and send data down a stream.
25240Sstevel@tonic-gate  * The caller will allocate and copyin any control part that precedes the
25258778SErik.Nordmark@Sun.COM  * message and pass that in as mctl.
25260Sstevel@tonic-gate  *
25270Sstevel@tonic-gate  * Caller should *not* hold sd_lock.
25280Sstevel@tonic-gate  * When EWOULDBLOCK is returned the caller has to redo the canputnext
25290Sstevel@tonic-gate  * under sd_lock in order to avoid missing a backenabling wakeup.
25300Sstevel@tonic-gate  *
25310Sstevel@tonic-gate  * Use iosize = -1 to not send any M_DATA. iosize = 0 sends zero-length M_DATA.
25320Sstevel@tonic-gate  *
25330Sstevel@tonic-gate  * Set MSG_IGNFLOW in flags to ignore flow control for hipri messages.
25340Sstevel@tonic-gate  * For sync streams we can only ignore flow control by reverting to using
25350Sstevel@tonic-gate  * putnext.
25360Sstevel@tonic-gate  *
25370Sstevel@tonic-gate  * If sd_maxblk is less than *iosize this routine might return without
25380Sstevel@tonic-gate  * transferring all of *iosize. In all cases, on return *iosize will contain
25390Sstevel@tonic-gate  * the amount of data that was transferred.
25400Sstevel@tonic-gate  */
25410Sstevel@tonic-gate static int
strput(struct stdata * stp,mblk_t * mctl,struct uio * uiop,ssize_t * iosize,int b_flag,int pri,int flags)25420Sstevel@tonic-gate strput(struct stdata *stp, mblk_t *mctl, struct uio *uiop, ssize_t *iosize,
25430Sstevel@tonic-gate     int b_flag, int pri, int flags)
25440Sstevel@tonic-gate {
25450Sstevel@tonic-gate 	struiod_t uiod;
25460Sstevel@tonic-gate 	mblk_t *mp;
25470Sstevel@tonic-gate 	queue_t *wqp = stp->sd_wrq;
25480Sstevel@tonic-gate 	int error = 0;
25490Sstevel@tonic-gate 	ssize_t count = *iosize;
25500Sstevel@tonic-gate 
25510Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&stp->sd_lock));
25520Sstevel@tonic-gate 
25530Sstevel@tonic-gate 	if (uiop != NULL && count >= 0)
25540Sstevel@tonic-gate 		flags |= stp->sd_struiowrq ? STRUIO_POSTPONE : 0;
25550Sstevel@tonic-gate 
25560Sstevel@tonic-gate 	if (!(flags & STRUIO_POSTPONE)) {
25570Sstevel@tonic-gate 		/*
25580Sstevel@tonic-gate 		 * Use regular canputnext, strmakedata, putnext sequence.
25590Sstevel@tonic-gate 		 */
25600Sstevel@tonic-gate 		if (pri == 0) {
25610Sstevel@tonic-gate 			if (!canputnext(wqp) && !(flags & MSG_IGNFLOW)) {
25620Sstevel@tonic-gate 				freemsg(mctl);
25630Sstevel@tonic-gate 				return (EWOULDBLOCK);
25640Sstevel@tonic-gate 			}
25650Sstevel@tonic-gate 		} else {
25660Sstevel@tonic-gate 			if (!(flags & MSG_IGNFLOW) && !bcanputnext(wqp, pri)) {
25670Sstevel@tonic-gate 				freemsg(mctl);
25680Sstevel@tonic-gate 				return (EWOULDBLOCK);
25690Sstevel@tonic-gate 			}
25700Sstevel@tonic-gate 		}
25710Sstevel@tonic-gate 
25720Sstevel@tonic-gate 		if ((error = strmakedata(iosize, uiop, stp, flags,
25735753Sgww 		    &mp)) != 0) {
25740Sstevel@tonic-gate 			freemsg(mctl);
25750Sstevel@tonic-gate 			/*
25760Sstevel@tonic-gate 			 * need to change return code to ENOMEM
25770Sstevel@tonic-gate 			 * so that this is not confused with
25780Sstevel@tonic-gate 			 * flow control, EAGAIN.
25790Sstevel@tonic-gate 			 */
25800Sstevel@tonic-gate 
25810Sstevel@tonic-gate 			if (error == EAGAIN)
25820Sstevel@tonic-gate 				return (ENOMEM);
25830Sstevel@tonic-gate 			else
25840Sstevel@tonic-gate 				return (error);
25850Sstevel@tonic-gate 		}
25860Sstevel@tonic-gate 		if (mctl != NULL) {
25870Sstevel@tonic-gate 			if (mctl->b_cont == NULL)
25880Sstevel@tonic-gate 				mctl->b_cont = mp;
25890Sstevel@tonic-gate 			else if (mp != NULL)
25900Sstevel@tonic-gate 				linkb(mctl, mp);
25910Sstevel@tonic-gate 			mp = mctl;
25920Sstevel@tonic-gate 		} else if (mp == NULL)
25930Sstevel@tonic-gate 			return (0);
25940Sstevel@tonic-gate 
25950Sstevel@tonic-gate 		mp->b_flag |= b_flag;
25960Sstevel@tonic-gate 		mp->b_band = (uchar_t)pri;
25970Sstevel@tonic-gate 
25980Sstevel@tonic-gate 		if (flags & MSG_IGNFLOW) {
25990Sstevel@tonic-gate 			/*
26000Sstevel@tonic-gate 			 * XXX Hack: Don't get stuck running service
26010Sstevel@tonic-gate 			 * procedures. This is needed for sockfs when
26020Sstevel@tonic-gate 			 * sending the unbind message out of the rput
26030Sstevel@tonic-gate 			 * procedure - we don't want a put procedure
26040Sstevel@tonic-gate 			 * to run service procedures.
26050Sstevel@tonic-gate 			 */
26060Sstevel@tonic-gate 			putnext(wqp, mp);
26070Sstevel@tonic-gate 		} else {
26080Sstevel@tonic-gate 			stream_willservice(stp);
26090Sstevel@tonic-gate 			putnext(wqp, mp);
26100Sstevel@tonic-gate 			stream_runservice(stp);
26110Sstevel@tonic-gate 		}
26120Sstevel@tonic-gate 		return (0);
26130Sstevel@tonic-gate 	}
26140Sstevel@tonic-gate 	/*
26150Sstevel@tonic-gate 	 * Stream supports rwnext() for the write side.
26160Sstevel@tonic-gate 	 */
26170Sstevel@tonic-gate 	if ((error = strmakedata(iosize, uiop, stp, flags, &mp)) != 0) {
26180Sstevel@tonic-gate 		freemsg(mctl);
26190Sstevel@tonic-gate 		/*
26200Sstevel@tonic-gate 		 * map EAGAIN to ENOMEM since EAGAIN means "flow controlled".
26210Sstevel@tonic-gate 		 */
26220Sstevel@tonic-gate 		return (error == EAGAIN ? ENOMEM : error);
26230Sstevel@tonic-gate 	}
26240Sstevel@tonic-gate 	if (mctl != NULL) {
26250Sstevel@tonic-gate 		if (mctl->b_cont == NULL)
26260Sstevel@tonic-gate 			mctl->b_cont = mp;
26270Sstevel@tonic-gate 		else if (mp != NULL)
26280Sstevel@tonic-gate 			linkb(mctl, mp);
26290Sstevel@tonic-gate 		mp = mctl;
26300Sstevel@tonic-gate 	} else if (mp == NULL) {
26310Sstevel@tonic-gate 		return (0);
26320Sstevel@tonic-gate 	}
26330Sstevel@tonic-gate 
26340Sstevel@tonic-gate 	mp->b_flag |= b_flag;
26350Sstevel@tonic-gate 	mp->b_band = (uchar_t)pri;
26360Sstevel@tonic-gate 
26370Sstevel@tonic-gate 	(void) uiodup(uiop, &uiod.d_uio, uiod.d_iov,
26385753Sgww 	    sizeof (uiod.d_iov) / sizeof (*uiod.d_iov));
26390Sstevel@tonic-gate 	uiod.d_uio.uio_offset = 0;
26400Sstevel@tonic-gate 	uiod.d_mp = mp;
26410Sstevel@tonic-gate 	error = rwnext(wqp, &uiod);
26420Sstevel@tonic-gate 	if (! uiod.d_mp) {
26430Sstevel@tonic-gate 		uioskip(uiop, *iosize);
26440Sstevel@tonic-gate 		return (error);
26450Sstevel@tonic-gate 	}
26460Sstevel@tonic-gate 	ASSERT(mp == uiod.d_mp);
26470Sstevel@tonic-gate 	if (error == EINVAL) {
26480Sstevel@tonic-gate 		/*
26490Sstevel@tonic-gate 		 * The stream plumbing must have changed while
26500Sstevel@tonic-gate 		 * we were away, so just turn off rwnext()s.
26510Sstevel@tonic-gate 		 */
26520Sstevel@tonic-gate 		error = 0;
26530Sstevel@tonic-gate 	} else if (error == EBUSY || error == EWOULDBLOCK) {
26540Sstevel@tonic-gate 		/*
26550Sstevel@tonic-gate 		 * Couldn't enter a perimeter or took a page fault,
26560Sstevel@tonic-gate 		 * so fall-back to putnext().
26570Sstevel@tonic-gate 		 */
26580Sstevel@tonic-gate 		error = 0;
26590Sstevel@tonic-gate 	} else {
26600Sstevel@tonic-gate 		freemsg(mp);
26610Sstevel@tonic-gate 		return (error);
26620Sstevel@tonic-gate 	}
26630Sstevel@tonic-gate 	/* Have to check canput before consuming data from the uio */
26640Sstevel@tonic-gate 	if (pri == 0) {
26650Sstevel@tonic-gate 		if (!canputnext(wqp) && !(flags & MSG_IGNFLOW)) {
26660Sstevel@tonic-gate 			freemsg(mp);
26670Sstevel@tonic-gate 			return (EWOULDBLOCK);
26680Sstevel@tonic-gate 		}
26690Sstevel@tonic-gate 	} else {
26700Sstevel@tonic-gate 		if (!bcanputnext(wqp, pri) && !(flags & MSG_IGNFLOW)) {
26710Sstevel@tonic-gate 			freemsg(mp);
26720Sstevel@tonic-gate 			return (EWOULDBLOCK);
26730Sstevel@tonic-gate 		}
26740Sstevel@tonic-gate 	}
26750Sstevel@tonic-gate 	ASSERT(mp == uiod.d_mp);
26760Sstevel@tonic-gate 	/* Copyin data from the uio */
26770Sstevel@tonic-gate 	if ((error = struioget(wqp, mp, &uiod, 0)) != 0) {
26780Sstevel@tonic-gate 		freemsg(mp);
26790Sstevel@tonic-gate 		return (error);
26800Sstevel@tonic-gate 	}
26810Sstevel@tonic-gate 	uioskip(uiop, *iosize);
26820Sstevel@tonic-gate 	if (flags & MSG_IGNFLOW) {
26830Sstevel@tonic-gate 		/*
26840Sstevel@tonic-gate 		 * XXX Hack: Don't get stuck running service procedures.
26850Sstevel@tonic-gate 		 * This is needed for sockfs when sending the unbind message
26860Sstevel@tonic-gate 		 * out of the rput procedure - we don't want a put procedure
26870Sstevel@tonic-gate 		 * to run service procedures.
26880Sstevel@tonic-gate 		 */
26890Sstevel@tonic-gate 		putnext(wqp, mp);
26900Sstevel@tonic-gate 	} else {
26910Sstevel@tonic-gate 		stream_willservice(stp);
26920Sstevel@tonic-gate 		putnext(wqp, mp);
26930Sstevel@tonic-gate 		stream_runservice(stp);
26940Sstevel@tonic-gate 	}
26950Sstevel@tonic-gate 	return (0);
26960Sstevel@tonic-gate }
26970Sstevel@tonic-gate 
26980Sstevel@tonic-gate /*
26990Sstevel@tonic-gate  * Write attempts to break the write request into messages conforming
27000Sstevel@tonic-gate  * with the minimum and maximum packet sizes set downstream.
27010Sstevel@tonic-gate  *
27020Sstevel@tonic-gate  * Write will not block if downstream queue is full and
27030Sstevel@tonic-gate  * O_NDELAY is set, otherwise it will block waiting for the queue to get room.
27040Sstevel@tonic-gate  *
27050Sstevel@tonic-gate  * A write of zero bytes gets packaged into a zero length message and sent
27060Sstevel@tonic-gate  * downstream like any other message.
27070Sstevel@tonic-gate  *
27080Sstevel@tonic-gate  * If buffers of the requested sizes are not available, the write will
27090Sstevel@tonic-gate  * sleep until the buffers become available.
27100Sstevel@tonic-gate  *
27110Sstevel@tonic-gate  * Write (if specified) will supply a write offset in a message if it
27120Sstevel@tonic-gate  * makes sense. This can be specified by downstream modules as part of
27130Sstevel@tonic-gate  * a M_SETOPTS message.  Write will not supply the write offset if it
27140Sstevel@tonic-gate  * cannot supply any data in a buffer.  In other words, write will never
27150Sstevel@tonic-gate  * send down an empty packet due to a write offset.
27160Sstevel@tonic-gate  */
27170Sstevel@tonic-gate /* ARGSUSED2 */
27180Sstevel@tonic-gate int
strwrite(struct vnode * vp,struct uio * uiop,cred_t * crp)27190Sstevel@tonic-gate strwrite(struct vnode *vp, struct uio *uiop, cred_t *crp)
27200Sstevel@tonic-gate {
2721741Smasputra 	return (strwrite_common(vp, uiop, crp, 0));
2722741Smasputra }
2723741Smasputra 
2724741Smasputra /* ARGSUSED2 */
2725741Smasputra int
strwrite_common(struct vnode * vp,struct uio * uiop,cred_t * crp,int wflag)2726741Smasputra strwrite_common(struct vnode *vp, struct uio *uiop, cred_t *crp, int wflag)
2727741Smasputra {
27280Sstevel@tonic-gate 	struct stdata *stp;
27290Sstevel@tonic-gate 	struct queue *wqp;
27300Sstevel@tonic-gate 	ssize_t rmin, rmax;
27310Sstevel@tonic-gate 	ssize_t iosize;
2732741Smasputra 	int waitflag;
27330Sstevel@tonic-gate 	int tempmode;
27340Sstevel@tonic-gate 	int error = 0;
27350Sstevel@tonic-gate 	int b_flag;
27360Sstevel@tonic-gate 
27370Sstevel@tonic-gate 	ASSERT(vp->v_stream);
27380Sstevel@tonic-gate 	stp = vp->v_stream;
27390Sstevel@tonic-gate 
27402712Snn35248 	mutex_enter(&stp->sd_lock);
27412712Snn35248 
27422712Snn35248 	if ((error = i_straccess(stp, JCWRITE)) != 0) {
27432712Snn35248 		mutex_exit(&stp->sd_lock);
27442712Snn35248 		return (error);
27452712Snn35248 	}
27460Sstevel@tonic-gate 
27470Sstevel@tonic-gate 	if (stp->sd_flag & (STWRERR|STRHUP|STPLEX)) {
27480Sstevel@tonic-gate 		error = strwriteable(stp, B_TRUE, B_TRUE);
27492712Snn35248 		if (error != 0) {
27502712Snn35248 			mutex_exit(&stp->sd_lock);
27510Sstevel@tonic-gate 			return (error);
27522712Snn35248 		}
27532712Snn35248 	}
27542712Snn35248 
27552712Snn35248 	mutex_exit(&stp->sd_lock);
27560Sstevel@tonic-gate 
27570Sstevel@tonic-gate 	wqp = stp->sd_wrq;
27580Sstevel@tonic-gate 
27590Sstevel@tonic-gate 	/* get these values from them cached in the stream head */
27600Sstevel@tonic-gate 	rmin = stp->sd_qn_minpsz;
27610Sstevel@tonic-gate 	rmax = stp->sd_qn_maxpsz;
27620Sstevel@tonic-gate 
27630Sstevel@tonic-gate 	/*
27640Sstevel@tonic-gate 	 * Check the min/max packet size constraints.  If min packet size
27650Sstevel@tonic-gate 	 * is non-zero, the write cannot be split into multiple messages
27660Sstevel@tonic-gate 	 * and still guarantee the size constraints.
27670Sstevel@tonic-gate 	 */
27680Sstevel@tonic-gate 	TRACE_1(TR_FAC_STREAMS_FR, TR_STRWRITE_IN, "strwrite in:q %p", wqp);
27690Sstevel@tonic-gate 
27700Sstevel@tonic-gate 	ASSERT((rmax >= 0) || (rmax == INFPSZ));
27710Sstevel@tonic-gate 	if (rmax == 0) {
27720Sstevel@tonic-gate 		return (0);
27730Sstevel@tonic-gate 	}
27740Sstevel@tonic-gate 	if (rmin > 0) {
27750Sstevel@tonic-gate 		if (uiop->uio_resid < rmin) {
27760Sstevel@tonic-gate 			TRACE_3(TR_FAC_STREAMS_FR, TR_STRWRITE_OUT,
27775753Sgww 			    "strwrite out:q %p out %d error %d",
27785753Sgww 			    wqp, 0, ERANGE);
27790Sstevel@tonic-gate 			return (ERANGE);
27800Sstevel@tonic-gate 		}
27810Sstevel@tonic-gate 		if ((rmax != INFPSZ) && (uiop->uio_resid > rmax)) {
27820Sstevel@tonic-gate 			TRACE_3(TR_FAC_STREAMS_FR, TR_STRWRITE_OUT,
27835753Sgww 			    "strwrite out:q %p out %d error %d",
27845753Sgww 			    wqp, 1, ERANGE);
27850Sstevel@tonic-gate 			return (ERANGE);
27860Sstevel@tonic-gate 		}
27870Sstevel@tonic-gate 	}
27880Sstevel@tonic-gate 
27890Sstevel@tonic-gate 	/*
27900Sstevel@tonic-gate 	 * Do until count satisfied or error.
27910Sstevel@tonic-gate 	 */
2792741Smasputra 	waitflag = WRITEWAIT | wflag;
27930Sstevel@tonic-gate 	if (stp->sd_flag & OLDNDELAY)
27940Sstevel@tonic-gate 		tempmode = uiop->uio_fmode & ~FNDELAY;
27950Sstevel@tonic-gate 	else
27960Sstevel@tonic-gate 		tempmode = uiop->uio_fmode;
27970Sstevel@tonic-gate 
27980Sstevel@tonic-gate 	if (rmax == INFPSZ)
27990Sstevel@tonic-gate 		rmax = uiop->uio_resid;
28000Sstevel@tonic-gate 
28010Sstevel@tonic-gate 	/*
28020Sstevel@tonic-gate 	 * Note that tempmode does not get used in strput/strmakedata
28030Sstevel@tonic-gate 	 * but only in strwaitq. The other routines use uio_fmode
28040Sstevel@tonic-gate 	 * unmodified.
28050Sstevel@tonic-gate 	 */
28060Sstevel@tonic-gate 
28070Sstevel@tonic-gate 	/* LINTED: constant in conditional context */
28080Sstevel@tonic-gate 	while (1) {	/* breaks when uio_resid reaches zero */
28090Sstevel@tonic-gate 		/*
28100Sstevel@tonic-gate 		 * Determine the size of the next message to be
28110Sstevel@tonic-gate 		 * packaged.  May have to break write into several
28120Sstevel@tonic-gate 		 * messages based on max packet size.
28130Sstevel@tonic-gate 		 */
28140Sstevel@tonic-gate 		iosize = MIN(uiop->uio_resid, rmax);
28150Sstevel@tonic-gate 
28160Sstevel@tonic-gate 		/*
28170Sstevel@tonic-gate 		 * Put block downstream when flow control allows it.
28180Sstevel@tonic-gate 		 */
28190Sstevel@tonic-gate 		if ((stp->sd_flag & STRDELIM) && (uiop->uio_resid == iosize))
28200Sstevel@tonic-gate 			b_flag = MSGDELIM;
28210Sstevel@tonic-gate 		else
28220Sstevel@tonic-gate 			b_flag = 0;
28230Sstevel@tonic-gate 
28240Sstevel@tonic-gate 		for (;;) {
28250Sstevel@tonic-gate 			int done = 0;
28260Sstevel@tonic-gate 
28275753Sgww 			error = strput(stp, NULL, uiop, &iosize, b_flag, 0, 0);
28280Sstevel@tonic-gate 			if (error == 0)
28290Sstevel@tonic-gate 				break;
28300Sstevel@tonic-gate 			if (error != EWOULDBLOCK)
28310Sstevel@tonic-gate 				goto out;
28320Sstevel@tonic-gate 
28330Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
28340Sstevel@tonic-gate 			/*
28350Sstevel@tonic-gate 			 * Check for a missed wakeup.
28360Sstevel@tonic-gate 			 * Needed since strput did not hold sd_lock across
28370Sstevel@tonic-gate 			 * the canputnext.
28380Sstevel@tonic-gate 			 */
28390Sstevel@tonic-gate 			if (canputnext(wqp)) {
28400Sstevel@tonic-gate 				/* Try again */
28410Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
28420Sstevel@tonic-gate 				continue;
28430Sstevel@tonic-gate 			}
28440Sstevel@tonic-gate 			TRACE_1(TR_FAC_STREAMS_FR, TR_STRWRITE_WAIT,
28455753Sgww 			    "strwrite wait:q %p wait", wqp);
28460Sstevel@tonic-gate 			if ((error = strwaitq(stp, waitflag, (ssize_t)0,
28470Sstevel@tonic-gate 			    tempmode, -1, &done)) != 0 || done) {
28480Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
28490Sstevel@tonic-gate 				if ((vp->v_type == VFIFO) &&
28500Sstevel@tonic-gate 				    (uiop->uio_fmode & FNDELAY) &&
28510Sstevel@tonic-gate 				    (error == EAGAIN))
28520Sstevel@tonic-gate 					error = 0;
28530Sstevel@tonic-gate 				goto out;
28540Sstevel@tonic-gate 			}
28550Sstevel@tonic-gate 			TRACE_1(TR_FAC_STREAMS_FR, TR_STRWRITE_WAKE,
28565753Sgww 			    "strwrite wake:q %p awakes", wqp);
28572712Snn35248 			if ((error = i_straccess(stp, JCWRITE)) != 0) {
28582712Snn35248 				mutex_exit(&stp->sd_lock);
28592712Snn35248 				goto out;
28602712Snn35248 			}
28610Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
28620Sstevel@tonic-gate 		}
28630Sstevel@tonic-gate 		waitflag |= NOINTR;
28640Sstevel@tonic-gate 		TRACE_2(TR_FAC_STREAMS_FR, TR_STRWRITE_RESID,
28655753Sgww 		    "strwrite resid:q %p uiop %p", wqp, uiop);
28660Sstevel@tonic-gate 		if (uiop->uio_resid) {
28670Sstevel@tonic-gate 			/* Recheck for errors - needed for sockets */
28680Sstevel@tonic-gate 			if ((stp->sd_wput_opt & SW_RECHECK_ERR) &&
28690Sstevel@tonic-gate 			    (stp->sd_flag & (STWRERR|STRHUP|STPLEX))) {
28700Sstevel@tonic-gate 				mutex_enter(&stp->sd_lock);
28710Sstevel@tonic-gate 				error = strwriteable(stp, B_FALSE, B_TRUE);
28720Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
28730Sstevel@tonic-gate 				if (error != 0)
28740Sstevel@tonic-gate 					return (error);
28750Sstevel@tonic-gate 			}
28760Sstevel@tonic-gate 			continue;
28770Sstevel@tonic-gate 		}
28780Sstevel@tonic-gate 		break;
28790Sstevel@tonic-gate 	}
28800Sstevel@tonic-gate out:
28810Sstevel@tonic-gate 	/*
28820Sstevel@tonic-gate 	 * For historical reasons, applications expect EAGAIN when a data
28830Sstevel@tonic-gate 	 * mblk_t cannot be allocated, so change ENOMEM back to EAGAIN.
28840Sstevel@tonic-gate 	 */
28850Sstevel@tonic-gate 	if (error == ENOMEM)
28860Sstevel@tonic-gate 		error = EAGAIN;
28870Sstevel@tonic-gate 	TRACE_3(TR_FAC_STREAMS_FR, TR_STRWRITE_OUT,
28885753Sgww 	    "strwrite out:q %p out %d error %d", wqp, 2, error);
28890Sstevel@tonic-gate 	return (error);
28900Sstevel@tonic-gate }
28910Sstevel@tonic-gate 
28920Sstevel@tonic-gate /*
28930Sstevel@tonic-gate  * Stream head write service routine.
28940Sstevel@tonic-gate  * Its job is to wake up any sleeping writers when a queue
28950Sstevel@tonic-gate  * downstream needs data (part of the flow control in putq and getq).
28960Sstevel@tonic-gate  * It also must wake anyone sleeping on a poll().
28970Sstevel@tonic-gate  * For stream head right below mux module, it must also invoke put procedure
28980Sstevel@tonic-gate  * of next downstream module.
28990Sstevel@tonic-gate  */
29000Sstevel@tonic-gate int
strwsrv(queue_t * q)29010Sstevel@tonic-gate strwsrv(queue_t *q)
29020Sstevel@tonic-gate {
29030Sstevel@tonic-gate 	struct stdata *stp;
29040Sstevel@tonic-gate 	queue_t *tq;
29050Sstevel@tonic-gate 	qband_t *qbp;
29060Sstevel@tonic-gate 	int i;
29070Sstevel@tonic-gate 	qband_t *myqbp;
29080Sstevel@tonic-gate 	int isevent;
29090Sstevel@tonic-gate 	unsigned char	qbf[NBAND];	/* band flushing backenable flags */
29100Sstevel@tonic-gate 
29110Sstevel@tonic-gate 	TRACE_1(TR_FAC_STREAMS_FR,
29125753Sgww 	    TR_STRWSRV, "strwsrv:q %p", q);
29130Sstevel@tonic-gate 	stp = (struct stdata *)q->q_ptr;
29140Sstevel@tonic-gate 	ASSERT(qclaimed(q));
29150Sstevel@tonic-gate 	mutex_enter(&stp->sd_lock);
29160Sstevel@tonic-gate 	ASSERT(!(stp->sd_flag & STPLEX));
29170Sstevel@tonic-gate 
29180Sstevel@tonic-gate 	if (stp->sd_flag & WSLEEP) {
29190Sstevel@tonic-gate 		stp->sd_flag &= ~WSLEEP;
29200Sstevel@tonic-gate 		cv_broadcast(&q->q_wait);
29210Sstevel@tonic-gate 	}
29220Sstevel@tonic-gate 	mutex_exit(&stp->sd_lock);
29230Sstevel@tonic-gate 
29240Sstevel@tonic-gate 	/* The other end of a stream pipe went away. */
29250Sstevel@tonic-gate 	if ((tq = q->q_next) == NULL) {
29260Sstevel@tonic-gate 		return (0);
29270Sstevel@tonic-gate 	}
29280Sstevel@tonic-gate 
29290Sstevel@tonic-gate 	/* Find the next module forward that has a service procedure */
29300Sstevel@tonic-gate 	claimstr(q);
29310Sstevel@tonic-gate 	tq = q->q_nfsrv;
29320Sstevel@tonic-gate 	ASSERT(tq != NULL);
29330Sstevel@tonic-gate 
29340Sstevel@tonic-gate 	if ((q->q_flag & QBACK)) {
29350Sstevel@tonic-gate 		if ((tq->q_flag & QFULL)) {
29360Sstevel@tonic-gate 			mutex_enter(QLOCK(tq));
29370Sstevel@tonic-gate 			if (!(tq->q_flag & QFULL)) {
29380Sstevel@tonic-gate 				mutex_exit(QLOCK(tq));
29390Sstevel@tonic-gate 				goto wakeup;
29400Sstevel@tonic-gate 			}
29410Sstevel@tonic-gate 			/*
29420Sstevel@tonic-gate 			 * The queue must have become full again. Set QWANTW
29430Sstevel@tonic-gate 			 * again so strwsrv will be back enabled when
29440Sstevel@tonic-gate 			 * the queue becomes non-full next time.
29450Sstevel@tonic-gate 			 */
29460Sstevel@tonic-gate 			tq->q_flag |= QWANTW;
29470Sstevel@tonic-gate 			mutex_exit(QLOCK(tq));
29480Sstevel@tonic-gate 		} else {
29490Sstevel@tonic-gate 		wakeup:
29500Sstevel@tonic-gate 			pollwakeup(&stp->sd_pollist, POLLWRNORM);
29510Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
29520Sstevel@tonic-gate 			if (stp->sd_sigflags & S_WRNORM)
29530Sstevel@tonic-gate 				strsendsig(stp->sd_siglist, S_WRNORM, 0, 0);
29540Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
29550Sstevel@tonic-gate 		}
29560Sstevel@tonic-gate 	}
29570Sstevel@tonic-gate 
29580Sstevel@tonic-gate 	isevent = 0;
29590Sstevel@tonic-gate 	i = 1;
29600Sstevel@tonic-gate 	bzero((caddr_t)qbf, NBAND);
29610Sstevel@tonic-gate 	mutex_enter(QLOCK(tq));
29620Sstevel@tonic-gate 	if ((myqbp = q->q_bandp) != NULL)
29630Sstevel@tonic-gate 		for (qbp = tq->q_bandp; qbp && myqbp; qbp = qbp->qb_next) {
29640Sstevel@tonic-gate 			ASSERT(myqbp);
29650Sstevel@tonic-gate 			if ((myqbp->qb_flag & QB_BACK)) {
29660Sstevel@tonic-gate 				if (qbp->qb_flag & QB_FULL) {
29670Sstevel@tonic-gate 					/*
29680Sstevel@tonic-gate 					 * The band must have become full again.
29690Sstevel@tonic-gate 					 * Set QB_WANTW again so strwsrv will
29700Sstevel@tonic-gate 					 * be back enabled when the band becomes
29710Sstevel@tonic-gate 					 * non-full next time.
29720Sstevel@tonic-gate 					 */
29730Sstevel@tonic-gate 					qbp->qb_flag |= QB_WANTW;
29740Sstevel@tonic-gate 				} else {
29750Sstevel@tonic-gate 					isevent = 1;
29760Sstevel@tonic-gate 					qbf[i] = 1;
29770Sstevel@tonic-gate 				}
29780Sstevel@tonic-gate 			}
29790Sstevel@tonic-gate 			myqbp = myqbp->qb_next;
29800Sstevel@tonic-gate 			i++;
29810Sstevel@tonic-gate 		}
29820Sstevel@tonic-gate 	mutex_exit(QLOCK(tq));
29830Sstevel@tonic-gate 
29840Sstevel@tonic-gate 	if (isevent) {
29855753Sgww 		for (i = tq->q_nband; i; i--) {
29865753Sgww 			if (qbf[i]) {
29875753Sgww 				pollwakeup(&stp->sd_pollist, POLLWRBAND);
29885753Sgww 				mutex_enter(&stp->sd_lock);
29895753Sgww 				if (stp->sd_sigflags & S_WRBAND)
29905753Sgww 					strsendsig(stp->sd_siglist, S_WRBAND,
29915753Sgww 					    (uchar_t)i, 0);
29925753Sgww 				mutex_exit(&stp->sd_lock);
29935753Sgww 			}
29945753Sgww 		}
29950Sstevel@tonic-gate 	}
29960Sstevel@tonic-gate 
29970Sstevel@tonic-gate 	releasestr(q);
29980Sstevel@tonic-gate 	return (0);
29990Sstevel@tonic-gate }
30000Sstevel@tonic-gate 
30010Sstevel@tonic-gate /*
30020Sstevel@tonic-gate  * Special case of strcopyin/strcopyout for copying
30030Sstevel@tonic-gate  * struct strioctl that can deal with both data
30040Sstevel@tonic-gate  * models.
30050Sstevel@tonic-gate  */
30060Sstevel@tonic-gate 
30070Sstevel@tonic-gate #ifdef	_LP64
30080Sstevel@tonic-gate 
30090Sstevel@tonic-gate static int
strcopyin_strioctl(void * from,void * to,int flag,int copyflag)30100Sstevel@tonic-gate strcopyin_strioctl(void *from, void *to, int flag, int copyflag)
30110Sstevel@tonic-gate {
30120Sstevel@tonic-gate 	struct	strioctl32 strioc32;
30130Sstevel@tonic-gate 	struct	strioctl *striocp;
30140Sstevel@tonic-gate 
30150Sstevel@tonic-gate 	if (copyflag & U_TO_K) {
30160Sstevel@tonic-gate 		ASSERT((copyflag & K_TO_K) == 0);
30170Sstevel@tonic-gate 
30180Sstevel@tonic-gate 		if ((flag & FMODELS) == DATAMODEL_ILP32) {
30190Sstevel@tonic-gate 			if (copyin(from, &strioc32, sizeof (strioc32)))
30200Sstevel@tonic-gate 				return (EFAULT);
30210Sstevel@tonic-gate 
30220Sstevel@tonic-gate 			striocp = (struct strioctl *)to;
30230Sstevel@tonic-gate 			striocp->ic_cmd	= strioc32.ic_cmd;
30240Sstevel@tonic-gate 			striocp->ic_timout = strioc32.ic_timout;
30250Sstevel@tonic-gate 			striocp->ic_len	= strioc32.ic_len;
30260Sstevel@tonic-gate 			striocp->ic_dp	= (char *)(uintptr_t)strioc32.ic_dp;
30270Sstevel@tonic-gate 
30280Sstevel@tonic-gate 		} else { /* NATIVE data model */
30290Sstevel@tonic-gate 			if (copyin(from, to, sizeof (struct strioctl))) {
30300Sstevel@tonic-gate 				return (EFAULT);
30310Sstevel@tonic-gate 			} else {
30320Sstevel@tonic-gate 				return (0);
30330Sstevel@tonic-gate 			}
30340Sstevel@tonic-gate 		}
30350Sstevel@tonic-gate 	} else {
30360Sstevel@tonic-gate 		ASSERT(copyflag & K_TO_K);
30370Sstevel@tonic-gate 		bcopy(from, to, sizeof (struct strioctl));
30380Sstevel@tonic-gate 	}
30390Sstevel@tonic-gate 	return (0);
30400Sstevel@tonic-gate }
30410Sstevel@tonic-gate 
30420Sstevel@tonic-gate static int
strcopyout_strioctl(void * from,void * to,int flag,int copyflag)30430Sstevel@tonic-gate strcopyout_strioctl(void *from, void *to, int flag, int copyflag)
30440Sstevel@tonic-gate {
30450Sstevel@tonic-gate 	struct	strioctl32 strioc32;
30460Sstevel@tonic-gate 	struct	strioctl *striocp;
30470Sstevel@tonic-gate 
30480Sstevel@tonic-gate 	if (copyflag & U_TO_K) {
30490Sstevel@tonic-gate 		ASSERT((copyflag & K_TO_K) == 0);
30500Sstevel@tonic-gate 
30510Sstevel@tonic-gate 		if ((flag & FMODELS) == DATAMODEL_ILP32) {
30520Sstevel@tonic-gate 			striocp = (struct strioctl *)from;
30530Sstevel@tonic-gate 			strioc32.ic_cmd	= striocp->ic_cmd;
30540Sstevel@tonic-gate 			strioc32.ic_timout = striocp->ic_timout;
30550Sstevel@tonic-gate 			strioc32.ic_len	= striocp->ic_len;
30560Sstevel@tonic-gate 			strioc32.ic_dp	= (caddr32_t)(uintptr_t)striocp->ic_dp;
30570Sstevel@tonic-gate 			ASSERT((char *)(uintptr_t)strioc32.ic_dp ==
30580Sstevel@tonic-gate 			    striocp->ic_dp);
30590Sstevel@tonic-gate 
30600Sstevel@tonic-gate 			if (copyout(&strioc32, to, sizeof (strioc32)))
30610Sstevel@tonic-gate 				return (EFAULT);
30620Sstevel@tonic-gate 
30630Sstevel@tonic-gate 		} else { /* NATIVE data model */
30640Sstevel@tonic-gate 			if (copyout(from, to, sizeof (struct strioctl))) {
30650Sstevel@tonic-gate 				return (EFAULT);
30660Sstevel@tonic-gate 			} else {
30670Sstevel@tonic-gate 				return (0);
30680Sstevel@tonic-gate 			}
30690Sstevel@tonic-gate 		}
30700Sstevel@tonic-gate 	} else {
30710Sstevel@tonic-gate 		ASSERT(copyflag & K_TO_K);
30720Sstevel@tonic-gate 		bcopy(from, to, sizeof (struct strioctl));
30730Sstevel@tonic-gate 	}
30740Sstevel@tonic-gate 	return (0);
30750Sstevel@tonic-gate }
30760Sstevel@tonic-gate 
30770Sstevel@tonic-gate #else	/* ! _LP64 */
30780Sstevel@tonic-gate 
30790Sstevel@tonic-gate /* ARGSUSED2 */
30800Sstevel@tonic-gate static int
strcopyin_strioctl(void * from,void * to,int flag,int copyflag)30810Sstevel@tonic-gate strcopyin_strioctl(void *from, void *to, int flag, int copyflag)
30820Sstevel@tonic-gate {
30830Sstevel@tonic-gate 	return (strcopyin(from, to, sizeof (struct strioctl), copyflag));
30840Sstevel@tonic-gate }
30850Sstevel@tonic-gate 
30860Sstevel@tonic-gate /* ARGSUSED2 */
30870Sstevel@tonic-gate static int
strcopyout_strioctl(void * from,void * to,int flag,int copyflag)30880Sstevel@tonic-gate strcopyout_strioctl(void *from, void *to, int flag, int copyflag)
30890Sstevel@tonic-gate {
30900Sstevel@tonic-gate 	return (strcopyout(from, to, sizeof (struct strioctl), copyflag));
30910Sstevel@tonic-gate }
30920Sstevel@tonic-gate 
30930Sstevel@tonic-gate #endif	/* _LP64 */
30940Sstevel@tonic-gate 
30950Sstevel@tonic-gate /*
30960Sstevel@tonic-gate  * Determine type of job control semantics expected by user.  The
30970Sstevel@tonic-gate  * possibilities are:
30980Sstevel@tonic-gate  *	JCREAD	- Behaves like read() on fd; send SIGTTIN
30990Sstevel@tonic-gate  *	JCWRITE	- Behaves like write() on fd; send SIGTTOU if TOSTOP set
31000Sstevel@tonic-gate  *	JCSETP	- Sets a value in the stream; send SIGTTOU, ignore TOSTOP
31010Sstevel@tonic-gate  *	JCGETP	- Gets a value in the stream; no signals.
31020Sstevel@tonic-gate  * See straccess in strsubr.c for usage of these values.
31030Sstevel@tonic-gate  *
31040Sstevel@tonic-gate  * This routine also returns -1 for I_STR as a special case; the
31050Sstevel@tonic-gate  * caller must call again with the real ioctl number for
31060Sstevel@tonic-gate  * classification.
31070Sstevel@tonic-gate  */
31080Sstevel@tonic-gate static int
job_control_type(int cmd)31090Sstevel@tonic-gate job_control_type(int cmd)
31100Sstevel@tonic-gate {
31110Sstevel@tonic-gate 	switch (cmd) {
31120Sstevel@tonic-gate 	case I_STR:
31130Sstevel@tonic-gate 		return (-1);
31140Sstevel@tonic-gate 
31150Sstevel@tonic-gate 	case I_RECVFD:
31160Sstevel@tonic-gate 	case I_E_RECVFD:
31170Sstevel@tonic-gate 		return (JCREAD);
31180Sstevel@tonic-gate 
31190Sstevel@tonic-gate 	case I_FDINSERT:
31200Sstevel@tonic-gate 	case I_SENDFD:
31210Sstevel@tonic-gate 		return (JCWRITE);
31220Sstevel@tonic-gate 
31230Sstevel@tonic-gate 	case TCSETA:
31240Sstevel@tonic-gate 	case TCSETAW:
31250Sstevel@tonic-gate 	case TCSETAF:
31260Sstevel@tonic-gate 	case TCSBRK:
31270Sstevel@tonic-gate 	case TCXONC:
31280Sstevel@tonic-gate 	case TCFLSH:
31290Sstevel@tonic-gate 	case TCDSET:	/* Obsolete */
31300Sstevel@tonic-gate 	case TIOCSWINSZ:
31310Sstevel@tonic-gate 	case TCSETS:
31320Sstevel@tonic-gate 	case TCSETSW:
31330Sstevel@tonic-gate 	case TCSETSF:
31340Sstevel@tonic-gate 	case TIOCSETD:
31350Sstevel@tonic-gate 	case TIOCHPCL:
31360Sstevel@tonic-gate 	case TIOCSETP:
31370Sstevel@tonic-gate 	case TIOCSETN:
31380Sstevel@tonic-gate 	case TIOCEXCL:
31390Sstevel@tonic-gate 	case TIOCNXCL:
31400Sstevel@tonic-gate 	case TIOCFLUSH:
31410Sstevel@tonic-gate 	case TIOCSETC:
31420Sstevel@tonic-gate 	case TIOCLBIS:
31430Sstevel@tonic-gate 	case TIOCLBIC:
31440Sstevel@tonic-gate 	case TIOCLSET:
31450Sstevel@tonic-gate 	case TIOCSBRK:
31460Sstevel@tonic-gate 	case TIOCCBRK:
31470Sstevel@tonic-gate 	case TIOCSDTR:
31480Sstevel@tonic-gate 	case TIOCCDTR:
31490Sstevel@tonic-gate 	case TIOCSLTC:
31500Sstevel@tonic-gate 	case TIOCSTOP:
31510Sstevel@tonic-gate 	case TIOCSTART:
31520Sstevel@tonic-gate 	case TIOCSTI:
31530Sstevel@tonic-gate 	case TIOCSPGRP:
31540Sstevel@tonic-gate 	case TIOCMSET:
31550Sstevel@tonic-gate 	case TIOCMBIS:
31560Sstevel@tonic-gate 	case TIOCMBIC:
31570Sstevel@tonic-gate 	case TIOCREMOTE:
31580Sstevel@tonic-gate 	case TIOCSIGNAL:
31590Sstevel@tonic-gate 	case LDSETT:
31600Sstevel@tonic-gate 	case LDSMAP:	/* Obsolete */
31610Sstevel@tonic-gate 	case DIOCSETP:
31620Sstevel@tonic-gate 	case I_FLUSH:
31630Sstevel@tonic-gate 	case I_SRDOPT:
31640Sstevel@tonic-gate 	case I_SETSIG:
31650Sstevel@tonic-gate 	case I_SWROPT:
31660Sstevel@tonic-gate 	case I_FLUSHBAND:
31670Sstevel@tonic-gate 	case I_SETCLTIME:
31680Sstevel@tonic-gate 	case I_SERROPT:
31690Sstevel@tonic-gate 	case I_ESETSIG:
31700Sstevel@tonic-gate 	case FIONBIO:
31710Sstevel@tonic-gate 	case FIOASYNC:
31720Sstevel@tonic-gate 	case FIOSETOWN:
31730Sstevel@tonic-gate 	case JBOOT:	/* Obsolete */
31740Sstevel@tonic-gate 	case JTERM:	/* Obsolete */
31750Sstevel@tonic-gate 	case JTIMOM:	/* Obsolete */
31760Sstevel@tonic-gate 	case JZOMBOOT:	/* Obsolete */
31770Sstevel@tonic-gate 	case JAGENT:	/* Obsolete */
31780Sstevel@tonic-gate 	case JTRUN:	/* Obsolete */
31790Sstevel@tonic-gate 	case JXTPROTO:	/* Obsolete */
31800Sstevel@tonic-gate 		return (JCSETP);
31810Sstevel@tonic-gate 	}
31820Sstevel@tonic-gate 
31830Sstevel@tonic-gate 	return (JCGETP);
31840Sstevel@tonic-gate }
31850Sstevel@tonic-gate 
31860Sstevel@tonic-gate /*
31870Sstevel@tonic-gate  * ioctl for streams
31880Sstevel@tonic-gate  */
31890Sstevel@tonic-gate int
strioctl(struct vnode * vp,int cmd,intptr_t arg,int flag,int copyflag,cred_t * crp,int * rvalp)31900Sstevel@tonic-gate strioctl(struct vnode *vp, int cmd, intptr_t arg, int flag, int copyflag,
31910Sstevel@tonic-gate     cred_t *crp, int *rvalp)
31920Sstevel@tonic-gate {
31930Sstevel@tonic-gate 	struct stdata *stp;
31946583Smeem 	struct strcmd *scp;
31950Sstevel@tonic-gate 	struct strioctl strioc;
31960Sstevel@tonic-gate 	struct uio uio;
31970Sstevel@tonic-gate 	struct iovec iov;
31980Sstevel@tonic-gate 	int access;
31990Sstevel@tonic-gate 	mblk_t *mp;
32000Sstevel@tonic-gate 	int error = 0;
32010Sstevel@tonic-gate 	int done = 0;
32020Sstevel@tonic-gate 	ssize_t	rmin, rmax;
32030Sstevel@tonic-gate 	queue_t *wrq;
32040Sstevel@tonic-gate 	queue_t *rdq;
32050Sstevel@tonic-gate 	boolean_t kioctl = B_FALSE;
320611861SMarek.Pospisil@Sun.COM 	uint32_t auditing = AU_AUDITING();
32070Sstevel@tonic-gate 
32080Sstevel@tonic-gate 	if (flag & FKIOCTL) {
32090Sstevel@tonic-gate 		copyflag = K_TO_K;
32100Sstevel@tonic-gate 		kioctl = B_TRUE;
32110Sstevel@tonic-gate 	}
32120Sstevel@tonic-gate 	ASSERT(vp->v_stream);
32130Sstevel@tonic-gate 	ASSERT(copyflag == U_TO_K || copyflag == K_TO_K);
32140Sstevel@tonic-gate 	stp = vp->v_stream;
32150Sstevel@tonic-gate 
32160Sstevel@tonic-gate 	TRACE_3(TR_FAC_STREAMS_FR, TR_IOCTL_ENTER,
32175753Sgww 	    "strioctl:stp %p cmd %X arg %lX", stp, cmd, arg);
32185753Sgww 
32190Sstevel@tonic-gate 	/*
32200Sstevel@tonic-gate 	 * If the copy is kernel to kernel, make sure that the FNATIVE
32210Sstevel@tonic-gate 	 * flag is set.  After this it would be a serious error to have
32220Sstevel@tonic-gate 	 * no model flag.
32230Sstevel@tonic-gate 	 */
32240Sstevel@tonic-gate 	if (copyflag == K_TO_K)
32250Sstevel@tonic-gate 		flag = (flag & ~FMODELS) | FNATIVE;
32260Sstevel@tonic-gate 
32270Sstevel@tonic-gate 	ASSERT((flag & FMODELS) != 0);
32280Sstevel@tonic-gate 
32290Sstevel@tonic-gate 	wrq = stp->sd_wrq;
32300Sstevel@tonic-gate 	rdq = _RD(wrq);
32310Sstevel@tonic-gate 
32320Sstevel@tonic-gate 	access = job_control_type(cmd);
32330Sstevel@tonic-gate 
32340Sstevel@tonic-gate 	/* We should never see these here, should be handled by iwscn */
32350Sstevel@tonic-gate 	if (cmd == SRIOCSREDIR || cmd == SRIOCISREDIR)
32360Sstevel@tonic-gate 		return (EINVAL);
32370Sstevel@tonic-gate 
32382712Snn35248 	mutex_enter(&stp->sd_lock);
32392712Snn35248 	if ((access != -1) && ((error = i_straccess(stp, access)) != 0)) {
32402712Snn35248 		mutex_exit(&stp->sd_lock);
32412712Snn35248 		return (error);
32422712Snn35248 	}
32432712Snn35248 	mutex_exit(&stp->sd_lock);
32440Sstevel@tonic-gate 
32450Sstevel@tonic-gate 	/*
32460Sstevel@tonic-gate 	 * Check for sgttyb-related ioctls first, and complain as
32470Sstevel@tonic-gate 	 * necessary.
32480Sstevel@tonic-gate 	 */
32490Sstevel@tonic-gate 	switch (cmd) {
32500Sstevel@tonic-gate 	case TIOCGETP:
32510Sstevel@tonic-gate 	case TIOCSETP:
32520Sstevel@tonic-gate 	case TIOCSETN:
32530Sstevel@tonic-gate 		if (sgttyb_handling >= 2 && !sgttyb_complaint) {
32540Sstevel@tonic-gate 			sgttyb_complaint = B_TRUE;
32550Sstevel@tonic-gate 			cmn_err(CE_NOTE,
32560Sstevel@tonic-gate 			    "application used obsolete TIOC[GS]ET");
32570Sstevel@tonic-gate 		}
32580Sstevel@tonic-gate 		if (sgttyb_handling >= 3) {
32590Sstevel@tonic-gate 			tsignal(curthread, SIGSYS);
32600Sstevel@tonic-gate 			return (EIO);
32610Sstevel@tonic-gate 		}
32620Sstevel@tonic-gate 		break;
32630Sstevel@tonic-gate 	}
32640Sstevel@tonic-gate 
32650Sstevel@tonic-gate 	mutex_enter(&stp->sd_lock);
32660Sstevel@tonic-gate 
32670Sstevel@tonic-gate 	switch (cmd) {
32680Sstevel@tonic-gate 	case I_RECVFD:
32690Sstevel@tonic-gate 	case I_E_RECVFD:
32700Sstevel@tonic-gate 	case I_PEEK:
32710Sstevel@tonic-gate 	case I_NREAD:
32720Sstevel@tonic-gate 	case FIONREAD:
32730Sstevel@tonic-gate 	case FIORDCHK:
32740Sstevel@tonic-gate 	case I_ATMARK:
32750Sstevel@tonic-gate 	case FIONBIO:
32760Sstevel@tonic-gate 	case FIOASYNC:
32770Sstevel@tonic-gate 		if (stp->sd_flag & (STRDERR|STPLEX)) {
32780Sstevel@tonic-gate 			error = strgeterr(stp, STRDERR|STPLEX, 0);
32790Sstevel@tonic-gate 			if (error != 0) {
32800Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
32810Sstevel@tonic-gate 				return (error);
32820Sstevel@tonic-gate 			}
32830Sstevel@tonic-gate 		}
32840Sstevel@tonic-gate 		break;
32850Sstevel@tonic-gate 
32860Sstevel@tonic-gate 	default:
32870Sstevel@tonic-gate 		if (stp->sd_flag & (STRDERR|STWRERR|STPLEX)) {
32880Sstevel@tonic-gate 			error = strgeterr(stp, STRDERR|STWRERR|STPLEX, 0);
32890Sstevel@tonic-gate 			if (error != 0) {
32900Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
32910Sstevel@tonic-gate 				return (error);
32920Sstevel@tonic-gate 			}
32930Sstevel@tonic-gate 		}
32940Sstevel@tonic-gate 	}
32950Sstevel@tonic-gate 
32960Sstevel@tonic-gate 	mutex_exit(&stp->sd_lock);
32970Sstevel@tonic-gate 
32980Sstevel@tonic-gate 	switch (cmd) {
32990Sstevel@tonic-gate 	default:
33000Sstevel@tonic-gate 		/*
33010Sstevel@tonic-gate 		 * The stream head has hardcoded knowledge of a
33020Sstevel@tonic-gate 		 * miscellaneous collection of terminal-, keyboard- and
33030Sstevel@tonic-gate 		 * mouse-related ioctls, enumerated below.  This hardcoded
33040Sstevel@tonic-gate 		 * knowledge allows the stream head to automatically
33050Sstevel@tonic-gate 		 * convert transparent ioctl requests made by userland
33060Sstevel@tonic-gate 		 * programs into I_STR ioctls which many old STREAMS
33070Sstevel@tonic-gate 		 * modules and drivers require.
33080Sstevel@tonic-gate 		 *
33090Sstevel@tonic-gate 		 * No new ioctls should ever be added to this list.
33100Sstevel@tonic-gate 		 * Instead, the STREAMS module or driver should be written
33110Sstevel@tonic-gate 		 * to either handle transparent ioctls or require any
33120Sstevel@tonic-gate 		 * userland programs to use I_STR ioctls (by returning
33130Sstevel@tonic-gate 		 * EINVAL to any transparent ioctl requests).
33140Sstevel@tonic-gate 		 *
33150Sstevel@tonic-gate 		 * More importantly, removing ioctls from this list should
33160Sstevel@tonic-gate 		 * be done with the utmost care, since our STREAMS modules
33170Sstevel@tonic-gate 		 * and drivers *count* on the stream head performing this
33180Sstevel@tonic-gate 		 * conversion, and thus may panic while processing
33190Sstevel@tonic-gate 		 * transparent ioctl request for one of these ioctls (keep
33200Sstevel@tonic-gate 		 * in mind that third party modules and drivers may have
33210Sstevel@tonic-gate 		 * similar problems).
33220Sstevel@tonic-gate 		 */
33230Sstevel@tonic-gate 		if (((cmd & IOCTYPE) == LDIOC) ||
33240Sstevel@tonic-gate 		    ((cmd & IOCTYPE) == tIOC) ||
33250Sstevel@tonic-gate 		    ((cmd & IOCTYPE) == TIOC) ||
33260Sstevel@tonic-gate 		    ((cmd & IOCTYPE) == KIOC) ||
33270Sstevel@tonic-gate 		    ((cmd & IOCTYPE) == MSIOC) ||
33280Sstevel@tonic-gate 		    ((cmd & IOCTYPE) == VUIOC)) {
33290Sstevel@tonic-gate 			/*
33300Sstevel@tonic-gate 			 * The ioctl is a tty ioctl - set up strioc buffer
33310Sstevel@tonic-gate 			 * and call strdoioctl() to do the work.
33320Sstevel@tonic-gate 			 */
33330Sstevel@tonic-gate 			if (stp->sd_flag & STRHUP)
33340Sstevel@tonic-gate 				return (ENXIO);
33350Sstevel@tonic-gate 			strioc.ic_cmd = cmd;
33360Sstevel@tonic-gate 			strioc.ic_timout = INFTIM;
33370Sstevel@tonic-gate 
33380Sstevel@tonic-gate 			switch (cmd) {
33390Sstevel@tonic-gate 
33400Sstevel@tonic-gate 			case TCXONC:
33410Sstevel@tonic-gate 			case TCSBRK:
33420Sstevel@tonic-gate 			case TCFLSH:
33430Sstevel@tonic-gate 			case TCDSET:
33440Sstevel@tonic-gate 				{
33450Sstevel@tonic-gate 				int native_arg = (int)arg;
33460Sstevel@tonic-gate 				strioc.ic_len = sizeof (int);
33470Sstevel@tonic-gate 				strioc.ic_dp = (char *)&native_arg;
33480Sstevel@tonic-gate 				return (strdoioctl(stp, &strioc, flag,
33490Sstevel@tonic-gate 				    K_TO_K, crp, rvalp));
33500Sstevel@tonic-gate 				}
33510Sstevel@tonic-gate 
33520Sstevel@tonic-gate 			case TCSETA:
33530Sstevel@tonic-gate 			case TCSETAW:
33540Sstevel@tonic-gate 			case TCSETAF:
33550Sstevel@tonic-gate 				strioc.ic_len = sizeof (struct termio);
33560Sstevel@tonic-gate 				strioc.ic_dp = (char *)arg;
33570Sstevel@tonic-gate 				return (strdoioctl(stp, &strioc, flag,
33585753Sgww 				    copyflag, crp, rvalp));
33590Sstevel@tonic-gate 
33600Sstevel@tonic-gate 			case TCSETS:
33610Sstevel@tonic-gate 			case TCSETSW:
33620Sstevel@tonic-gate 			case TCSETSF:
33630Sstevel@tonic-gate 				strioc.ic_len = sizeof (struct termios);
33640Sstevel@tonic-gate 				strioc.ic_dp = (char *)arg;
33650Sstevel@tonic-gate 				return (strdoioctl(stp, &strioc, flag,
33665753Sgww 				    copyflag, crp, rvalp));
33670Sstevel@tonic-gate 
33680Sstevel@tonic-gate 			case LDSETT:
33690Sstevel@tonic-gate 				strioc.ic_len = sizeof (struct termcb);
33700Sstevel@tonic-gate 				strioc.ic_dp = (char *)arg;
33710Sstevel@tonic-gate 				return (strdoioctl(stp, &strioc, flag,
33725753Sgww 				    copyflag, crp, rvalp));
33730Sstevel@tonic-gate 
33740Sstevel@tonic-gate 			case TIOCSETP:
33750Sstevel@tonic-gate 				strioc.ic_len = sizeof (struct sgttyb);
33760Sstevel@tonic-gate 				strioc.ic_dp = (char *)arg;
33770Sstevel@tonic-gate 				return (strdoioctl(stp, &strioc, flag,
33785753Sgww 				    copyflag, crp, rvalp));
33790Sstevel@tonic-gate 
33800Sstevel@tonic-gate 			case TIOCSTI:
33810Sstevel@tonic-gate 				if ((flag & FREAD) == 0 &&
33820Sstevel@tonic-gate 				    secpolicy_sti(crp) != 0) {
33830Sstevel@tonic-gate 					return (EPERM);
33840Sstevel@tonic-gate 				}
33852712Snn35248 				mutex_enter(&stp->sd_lock);
33862712Snn35248 				mutex_enter(&curproc->p_splock);
33872712Snn35248 				if (stp->sd_sidp != curproc->p_sessp->s_sidp &&
33880Sstevel@tonic-gate 				    secpolicy_sti(crp) != 0) {
33892712Snn35248 					mutex_exit(&curproc->p_splock);
33902712Snn35248 					mutex_exit(&stp->sd_lock);
33910Sstevel@tonic-gate 					return (EACCES);
33920Sstevel@tonic-gate 				}
33932712Snn35248 				mutex_exit(&curproc->p_splock);
33942712Snn35248 				mutex_exit(&stp->sd_lock);
33950Sstevel@tonic-gate 
33960Sstevel@tonic-gate 				strioc.ic_len = sizeof (char);
33970Sstevel@tonic-gate 				strioc.ic_dp = (char *)arg;
33980Sstevel@tonic-gate 				return (strdoioctl(stp, &strioc, flag,
33995753Sgww 				    copyflag, crp, rvalp));
34000Sstevel@tonic-gate 
34010Sstevel@tonic-gate 			case TIOCSWINSZ:
34020Sstevel@tonic-gate 				strioc.ic_len = sizeof (struct winsize);
34030Sstevel@tonic-gate 				strioc.ic_dp = (char *)arg;
34040Sstevel@tonic-gate 				return (strdoioctl(stp, &strioc, flag,
34055753Sgww 				    copyflag, crp, rvalp));
34060Sstevel@tonic-gate 
34070Sstevel@tonic-gate 			case TIOCSSIZE:
34080Sstevel@tonic-gate 				strioc.ic_len = sizeof (struct ttysize);
34090Sstevel@tonic-gate 				strioc.ic_dp = (char *)arg;
34100Sstevel@tonic-gate 				return (strdoioctl(stp, &strioc, flag,
34115753Sgww 				    copyflag, crp, rvalp));
34120Sstevel@tonic-gate 
34130Sstevel@tonic-gate 			case TIOCSSOFTCAR:
34140Sstevel@tonic-gate 			case KIOCTRANS:
34150Sstevel@tonic-gate 			case KIOCTRANSABLE:
34160Sstevel@tonic-gate 			case KIOCCMD:
34170Sstevel@tonic-gate 			case KIOCSDIRECT:
34180Sstevel@tonic-gate 			case KIOCSCOMPAT:
34190Sstevel@tonic-gate 			case KIOCSKABORTEN:
34200Sstevel@tonic-gate 			case KIOCSRPTDELAY:
34210Sstevel@tonic-gate 			case KIOCSRPTRATE:
34220Sstevel@tonic-gate 			case VUIDSFORMAT:
34230Sstevel@tonic-gate 			case TIOCSPPS:
34240Sstevel@tonic-gate 				strioc.ic_len = sizeof (int);
34250Sstevel@tonic-gate 				strioc.ic_dp = (char *)arg;
34260Sstevel@tonic-gate 				return (strdoioctl(stp, &strioc, flag,
34275753Sgww 				    copyflag, crp, rvalp));
34280Sstevel@tonic-gate 
34290Sstevel@tonic-gate 			case KIOCSETKEY:
34300Sstevel@tonic-gate 			case KIOCGETKEY:
34310Sstevel@tonic-gate 				strioc.ic_len = sizeof (struct kiockey);
34320Sstevel@tonic-gate 				strioc.ic_dp = (char *)arg;
34330Sstevel@tonic-gate 				return (strdoioctl(stp, &strioc, flag,
34345753Sgww 				    copyflag, crp, rvalp));
34350Sstevel@tonic-gate 
34360Sstevel@tonic-gate 			case KIOCSKEY:
34370Sstevel@tonic-gate 			case KIOCGKEY:
34380Sstevel@tonic-gate 				strioc.ic_len = sizeof (struct kiockeymap);
34390Sstevel@tonic-gate 				strioc.ic_dp = (char *)arg;
34400Sstevel@tonic-gate 				return (strdoioctl(stp, &strioc, flag,
34415753Sgww 				    copyflag, crp, rvalp));
34420Sstevel@tonic-gate 
34430Sstevel@tonic-gate 			case KIOCSLED:
34440Sstevel@tonic-gate 				/* arg is a pointer to char */
34450Sstevel@tonic-gate 				strioc.ic_len = sizeof (char);
34460Sstevel@tonic-gate 				strioc.ic_dp = (char *)arg;
34470Sstevel@tonic-gate 				return (strdoioctl(stp, &strioc, flag,
34485753Sgww 				    copyflag, crp, rvalp));
34490Sstevel@tonic-gate 
34500Sstevel@tonic-gate 			case MSIOSETPARMS:
34510Sstevel@tonic-gate 				strioc.ic_len = sizeof (Ms_parms);
34520Sstevel@tonic-gate 				strioc.ic_dp = (char *)arg;
34530Sstevel@tonic-gate 				return (strdoioctl(stp, &strioc, flag,
34545753Sgww 				    copyflag, crp, rvalp));
34550Sstevel@tonic-gate 
34560Sstevel@tonic-gate 			case VUIDSADDR:
34570Sstevel@tonic-gate 			case VUIDGADDR:
34580Sstevel@tonic-gate 				strioc.ic_len = sizeof (struct vuid_addr_probe);
34590Sstevel@tonic-gate 				strioc.ic_dp = (char *)arg;
34600Sstevel@tonic-gate 				return (strdoioctl(stp, &strioc, flag,
34615753Sgww 				    copyflag, crp, rvalp));
34620Sstevel@tonic-gate 
34630Sstevel@tonic-gate 			/*
34640Sstevel@tonic-gate 			 * These M_IOCTL's don't require any data to be sent
34650Sstevel@tonic-gate 			 * downstream, and the driver will allocate and link
34660Sstevel@tonic-gate 			 * on its own mblk_t upon M_IOCACK -- thus we set
34670Sstevel@tonic-gate 			 * ic_len to zero and set ic_dp to arg so we know
34680Sstevel@tonic-gate 			 * where to copyout to later.
34690Sstevel@tonic-gate 			 */
34700Sstevel@tonic-gate 			case TIOCGSOFTCAR:
34710Sstevel@tonic-gate 			case TIOCGWINSZ:
34720Sstevel@tonic-gate 			case TIOCGSIZE:
34730Sstevel@tonic-gate 			case KIOCGTRANS:
34740Sstevel@tonic-gate 			case KIOCGTRANSABLE:
34750Sstevel@tonic-gate 			case KIOCTYPE:
34760Sstevel@tonic-gate 			case KIOCGDIRECT:
34770Sstevel@tonic-gate 			case KIOCGCOMPAT:
34780Sstevel@tonic-gate 			case KIOCLAYOUT:
34790Sstevel@tonic-gate 			case KIOCGLED:
34800Sstevel@tonic-gate 			case MSIOGETPARMS:
34810Sstevel@tonic-gate 			case MSIOBUTTONS:
34820Sstevel@tonic-gate 			case VUIDGFORMAT:
34830Sstevel@tonic-gate 			case TIOCGPPS:
34840Sstevel@tonic-gate 			case TIOCGPPSEV:
34850Sstevel@tonic-gate 			case TCGETA:
34860Sstevel@tonic-gate 			case TCGETS:
34870Sstevel@tonic-gate 			case LDGETT:
34880Sstevel@tonic-gate 			case TIOCGETP:
34890Sstevel@tonic-gate 			case KIOCGRPTDELAY:
34900Sstevel@tonic-gate 			case KIOCGRPTRATE:
34910Sstevel@tonic-gate 				strioc.ic_len = 0;
34920Sstevel@tonic-gate 				strioc.ic_dp = (char *)arg;
34930Sstevel@tonic-gate 				return (strdoioctl(stp, &strioc, flag,
34945753Sgww 				    copyflag, crp, rvalp));
34950Sstevel@tonic-gate 			}
34960Sstevel@tonic-gate 		}
34970Sstevel@tonic-gate 
34980Sstevel@tonic-gate 		/*
34990Sstevel@tonic-gate 		 * Unknown cmd - send it down as a transparent ioctl.
35000Sstevel@tonic-gate 		 */
35010Sstevel@tonic-gate 		strioc.ic_cmd = cmd;
35020Sstevel@tonic-gate 		strioc.ic_timout = INFTIM;
35030Sstevel@tonic-gate 		strioc.ic_len = TRANSPARENT;
35040Sstevel@tonic-gate 		strioc.ic_dp = (char *)&arg;
35050Sstevel@tonic-gate 
35060Sstevel@tonic-gate 		return (strdoioctl(stp, &strioc, flag, copyflag, crp, rvalp));
35070Sstevel@tonic-gate 
35080Sstevel@tonic-gate 	case I_STR:
35090Sstevel@tonic-gate 		/*
35100Sstevel@tonic-gate 		 * Stream ioctl.  Read in an strioctl buffer from the user
35110Sstevel@tonic-gate 		 * along with any data specified and send it downstream.
35120Sstevel@tonic-gate 		 * Strdoioctl will wait allow only one ioctl message at
35130Sstevel@tonic-gate 		 * a time, and waits for the acknowledgement.
35140Sstevel@tonic-gate 		 */
35150Sstevel@tonic-gate 
35160Sstevel@tonic-gate 		if (stp->sd_flag & STRHUP)
35170Sstevel@tonic-gate 			return (ENXIO);
35180Sstevel@tonic-gate 
35190Sstevel@tonic-gate 		error = strcopyin_strioctl((void *)arg, &strioc, flag,
35200Sstevel@tonic-gate 		    copyflag);
35210Sstevel@tonic-gate 		if (error != 0)
35220Sstevel@tonic-gate 			return (error);
35230Sstevel@tonic-gate 
35240Sstevel@tonic-gate 		if ((strioc.ic_len < 0) || (strioc.ic_timout < -1))
35250Sstevel@tonic-gate 			return (EINVAL);
35260Sstevel@tonic-gate 
35270Sstevel@tonic-gate 		access = job_control_type(strioc.ic_cmd);
35282712Snn35248 		mutex_enter(&stp->sd_lock);
35292712Snn35248 		if ((access != -1) &&
35302712Snn35248 		    ((error = i_straccess(stp, access)) != 0)) {
35312712Snn35248 			mutex_exit(&stp->sd_lock);
35320Sstevel@tonic-gate 			return (error);
35332712Snn35248 		}
35342712Snn35248 		mutex_exit(&stp->sd_lock);
35350Sstevel@tonic-gate 
35360Sstevel@tonic-gate 		/*
35370Sstevel@tonic-gate 		 * The I_STR facility provides a trap door for malicious
35380Sstevel@tonic-gate 		 * code to send down bogus streamio(7I) ioctl commands to
35390Sstevel@tonic-gate 		 * unsuspecting STREAMS modules and drivers which expect to
35400Sstevel@tonic-gate 		 * only get these messages from the stream head.
35410Sstevel@tonic-gate 		 * Explicitly prohibit any streamio ioctls which can be
35420Sstevel@tonic-gate 		 * passed downstream by the stream head.  Note that we do
35430Sstevel@tonic-gate 		 * not block all streamio ioctls because the ioctl
35440Sstevel@tonic-gate 		 * numberspace is not well managed and thus it's possible
35450Sstevel@tonic-gate 		 * that a module or driver's ioctl numbers may accidentally
35460Sstevel@tonic-gate 		 * collide with them.
35470Sstevel@tonic-gate 		 */
35480Sstevel@tonic-gate 		switch (strioc.ic_cmd) {
35490Sstevel@tonic-gate 		case I_LINK:
35500Sstevel@tonic-gate 		case I_PLINK:
35510Sstevel@tonic-gate 		case I_UNLINK:
35520Sstevel@tonic-gate 		case I_PUNLINK:
35530Sstevel@tonic-gate 		case _I_GETPEERCRED:
35540Sstevel@tonic-gate 		case _I_PLINK_LH:
35550Sstevel@tonic-gate 			return (EINVAL);
35560Sstevel@tonic-gate 		}
35570Sstevel@tonic-gate 
35580Sstevel@tonic-gate 		error = strdoioctl(stp, &strioc, flag, copyflag, crp, rvalp);
35590Sstevel@tonic-gate 		if (error == 0) {
35600Sstevel@tonic-gate 			error = strcopyout_strioctl(&strioc, (void *)arg,
35610Sstevel@tonic-gate 			    flag, copyflag);
35620Sstevel@tonic-gate 		}
35630Sstevel@tonic-gate 		return (error);
35640Sstevel@tonic-gate 
35656583Smeem 	case _I_CMD:
35666583Smeem 		/*
35676583Smeem 		 * Like I_STR, but without using M_IOC* messages and without
35686583Smeem 		 * copyins/copyouts beyond the passed-in argument.
35696583Smeem 		 */
35706583Smeem 		if (stp->sd_flag & STRHUP)
35716583Smeem 			return (ENXIO);
35726583Smeem 
35736583Smeem 		if ((scp = kmem_alloc(sizeof (strcmd_t), KM_NOSLEEP)) == NULL)
35746583Smeem 			return (ENOMEM);
35756583Smeem 
35766583Smeem 		if (copyin((void *)arg, scp, sizeof (strcmd_t))) {
35776583Smeem 			kmem_free(scp, sizeof (strcmd_t));
35786583Smeem 			return (EFAULT);
35796583Smeem 		}
35806583Smeem 
35816583Smeem 		access = job_control_type(scp->sc_cmd);
35826583Smeem 		mutex_enter(&stp->sd_lock);
35836583Smeem 		if (access != -1 && (error = i_straccess(stp, access)) != 0) {
35846583Smeem 			mutex_exit(&stp->sd_lock);
35856583Smeem 			kmem_free(scp, sizeof (strcmd_t));
35866583Smeem 			return (error);
35876583Smeem 		}
35886583Smeem 		mutex_exit(&stp->sd_lock);
35896583Smeem 
35906583Smeem 		*rvalp = 0;
35916583Smeem 		if ((error = strdocmd(stp, scp, crp)) == 0) {
35926583Smeem 			if (copyout(scp, (void *)arg, sizeof (strcmd_t)))
35936583Smeem 				error = EFAULT;
35946583Smeem 		}
35956583Smeem 		kmem_free(scp, sizeof (strcmd_t));
35966583Smeem 		return (error);
35976583Smeem 
35980Sstevel@tonic-gate 	case I_NREAD:
35990Sstevel@tonic-gate 		/*
36000Sstevel@tonic-gate 		 * Return number of bytes of data in first message
36010Sstevel@tonic-gate 		 * in queue in "arg" and return the number of messages
36020Sstevel@tonic-gate 		 * in queue in return value.
36030Sstevel@tonic-gate 		 */
36045753Sgww 	{
36050Sstevel@tonic-gate 		size_t	size;
36060Sstevel@tonic-gate 		int	retval;
36070Sstevel@tonic-gate 		int	count = 0;
36080Sstevel@tonic-gate 
36090Sstevel@tonic-gate 		mutex_enter(QLOCK(rdq));
36100Sstevel@tonic-gate 
36110Sstevel@tonic-gate 		size = msgdsize(rdq->q_first);
36120Sstevel@tonic-gate 		for (mp = rdq->q_first; mp != NULL; mp = mp->b_next)
36130Sstevel@tonic-gate 			count++;
36140Sstevel@tonic-gate 
36150Sstevel@tonic-gate 		mutex_exit(QLOCK(rdq));
36160Sstevel@tonic-gate 		if (stp->sd_struiordq) {
36170Sstevel@tonic-gate 			infod_t infod;
36180Sstevel@tonic-gate 
36190Sstevel@tonic-gate 			infod.d_cmd = INFOD_COUNT;
36200Sstevel@tonic-gate 			infod.d_count = 0;
36210Sstevel@tonic-gate 			if (count == 0) {
36220Sstevel@tonic-gate 				infod.d_cmd |= INFOD_FIRSTBYTES;
36230Sstevel@tonic-gate 				infod.d_bytes = 0;
36240Sstevel@tonic-gate 			}
36250Sstevel@tonic-gate 			infod.d_res = 0;
36260Sstevel@tonic-gate 			(void) infonext(rdq, &infod);
36270Sstevel@tonic-gate 			count += infod.d_count;
36280Sstevel@tonic-gate 			if (infod.d_res & INFOD_FIRSTBYTES)
36290Sstevel@tonic-gate 				size = infod.d_bytes;
36300Sstevel@tonic-gate 		}
36310Sstevel@tonic-gate 
36320Sstevel@tonic-gate 		/*
36330Sstevel@tonic-gate 		 * Drop down from size_t to the "int" required by the
36340Sstevel@tonic-gate 		 * interface.  Cap at INT_MAX.
36350Sstevel@tonic-gate 		 */
36360Sstevel@tonic-gate 		retval = MIN(size, INT_MAX);
36370Sstevel@tonic-gate 		error = strcopyout(&retval, (void *)arg, sizeof (retval),
36380Sstevel@tonic-gate 		    copyflag);
36390Sstevel@tonic-gate 		if (!error)
36400Sstevel@tonic-gate 			*rvalp = count;
36410Sstevel@tonic-gate 		return (error);
36425753Sgww 	}
36430Sstevel@tonic-gate 
36440Sstevel@tonic-gate 	case FIONREAD:
36450Sstevel@tonic-gate 		/*
36460Sstevel@tonic-gate 		 * Return number of bytes of data in all data messages
36470Sstevel@tonic-gate 		 * in queue in "arg".
36480Sstevel@tonic-gate 		 */
36495753Sgww 	{
36500Sstevel@tonic-gate 		size_t	size = 0;
36510Sstevel@tonic-gate 		int	retval;
36520Sstevel@tonic-gate 
36530Sstevel@tonic-gate 		mutex_enter(QLOCK(rdq));
36540Sstevel@tonic-gate 		for (mp = rdq->q_first; mp != NULL; mp = mp->b_next)
36550Sstevel@tonic-gate 			size += msgdsize(mp);
36560Sstevel@tonic-gate 		mutex_exit(QLOCK(rdq));
36570Sstevel@tonic-gate 
36580Sstevel@tonic-gate 		if (stp->sd_struiordq) {
36590Sstevel@tonic-gate 			infod_t infod;
36600Sstevel@tonic-gate 
36610Sstevel@tonic-gate 			infod.d_cmd = INFOD_BYTES;
36620Sstevel@tonic-gate 			infod.d_res = 0;
36630Sstevel@tonic-gate 			infod.d_bytes = 0;
36640Sstevel@tonic-gate 			(void) infonext(rdq, &infod);
36650Sstevel@tonic-gate 			size += infod.d_bytes;
36660Sstevel@tonic-gate 		}
36670Sstevel@tonic-gate 
36680Sstevel@tonic-gate 		/*
36690Sstevel@tonic-gate 		 * Drop down from size_t to the "int" required by the
36700Sstevel@tonic-gate 		 * interface.  Cap at INT_MAX.
36710Sstevel@tonic-gate 		 */
36720Sstevel@tonic-gate 		retval = MIN(size, INT_MAX);
36730Sstevel@tonic-gate 		error = strcopyout(&retval, (void *)arg, sizeof (retval),
36740Sstevel@tonic-gate 		    copyflag);
36750Sstevel@tonic-gate 
36760Sstevel@tonic-gate 		*rvalp = 0;
36770Sstevel@tonic-gate 		return (error);
36785753Sgww 	}
36790Sstevel@tonic-gate 	case FIORDCHK:
36800Sstevel@tonic-gate 		/*
36810Sstevel@tonic-gate 		 * FIORDCHK does not use arg value (like FIONREAD),
36820Sstevel@tonic-gate 		 * instead a count is returned. I_NREAD value may
36830Sstevel@tonic-gate 		 * not be accurate but safe. The real thing to do is
36840Sstevel@tonic-gate 		 * to add the msgdsizes of all data  messages until
36850Sstevel@tonic-gate 		 * a non-data message.
36860Sstevel@tonic-gate 		 */
36875753Sgww 	{
36880Sstevel@tonic-gate 		size_t size = 0;
36890Sstevel@tonic-gate 
36900Sstevel@tonic-gate 		mutex_enter(QLOCK(rdq));
36910Sstevel@tonic-gate 		for (mp = rdq->q_first; mp != NULL; mp = mp->b_next)
36920Sstevel@tonic-gate 			size += msgdsize(mp);
36930Sstevel@tonic-gate 		mutex_exit(QLOCK(rdq));
36940Sstevel@tonic-gate 
36950Sstevel@tonic-gate 		if (stp->sd_struiordq) {
36960Sstevel@tonic-gate 			infod_t infod;
36970Sstevel@tonic-gate 
36980Sstevel@tonic-gate 			infod.d_cmd = INFOD_BYTES;
36990Sstevel@tonic-gate 			infod.d_res = 0;
37000Sstevel@tonic-gate 			infod.d_bytes = 0;
37010Sstevel@tonic-gate 			(void) infonext(rdq, &infod);
37020Sstevel@tonic-gate 			size += infod.d_bytes;
37030Sstevel@tonic-gate 		}
37040Sstevel@tonic-gate 
37050Sstevel@tonic-gate 		/*
37060Sstevel@tonic-gate 		 * Since ioctl returns an int, and memory sizes under
37070Sstevel@tonic-gate 		 * LP64 may not fit, we return INT_MAX if the count was
37080Sstevel@tonic-gate 		 * actually greater.
37090Sstevel@tonic-gate 		 */
37100Sstevel@tonic-gate 		*rvalp = MIN(size, INT_MAX);
37110Sstevel@tonic-gate 		return (0);
37125753Sgww 	}
37130Sstevel@tonic-gate 
37140Sstevel@tonic-gate 	case I_FIND:
37150Sstevel@tonic-gate 		/*
37160Sstevel@tonic-gate 		 * Get module name.
37170Sstevel@tonic-gate 		 */
37185753Sgww 	{
37190Sstevel@tonic-gate 		char mname[FMNAMESZ + 1];
37200Sstevel@tonic-gate 		queue_t *q;
37210Sstevel@tonic-gate 
37220Sstevel@tonic-gate 		error = (copyflag & U_TO_K ? copyinstr : copystr)((void *)arg,
37230Sstevel@tonic-gate 		    mname, FMNAMESZ + 1, NULL);
37240Sstevel@tonic-gate 		if (error)
37250Sstevel@tonic-gate 			return ((error == ENAMETOOLONG) ? EINVAL : EFAULT);
37260Sstevel@tonic-gate 
37270Sstevel@tonic-gate 		/*
37280Sstevel@tonic-gate 		 * Return EINVAL if we're handed a bogus module name.
37290Sstevel@tonic-gate 		 */
37300Sstevel@tonic-gate 		if (fmodsw_find(mname, FMODSW_LOAD) == NULL) {
37310Sstevel@tonic-gate 			TRACE_0(TR_FAC_STREAMS_FR,
37325753Sgww 			    TR_I_CANT_FIND, "couldn't I_FIND");
37330Sstevel@tonic-gate 			return (EINVAL);
37340Sstevel@tonic-gate 		}
37350Sstevel@tonic-gate 
37360Sstevel@tonic-gate 		*rvalp = 0;
37370Sstevel@tonic-gate 
37380Sstevel@tonic-gate 		/* Look downstream to see if module is there. */
37390Sstevel@tonic-gate 		claimstr(stp->sd_wrq);
37400Sstevel@tonic-gate 		for (q = stp->sd_wrq->q_next; q; q = q->q_next) {
37418752SPeter.Memishian@Sun.COM 			if (q->q_flag & QREADR) {
37420Sstevel@tonic-gate 				q = NULL;
37430Sstevel@tonic-gate 				break;
37440Sstevel@tonic-gate 			}
37458752SPeter.Memishian@Sun.COM 			if (strcmp(mname, Q2NAME(q)) == 0)
37460Sstevel@tonic-gate 				break;
37470Sstevel@tonic-gate 		}
37480Sstevel@tonic-gate 		releasestr(stp->sd_wrq);
37490Sstevel@tonic-gate 
37500Sstevel@tonic-gate 		*rvalp = (q ? 1 : 0);
37510Sstevel@tonic-gate 		return (error);
37525753Sgww 	}
37530Sstevel@tonic-gate 
37540Sstevel@tonic-gate 	case I_PUSH:
37550Sstevel@tonic-gate 	case __I_PUSH_NOCTTY:
37560Sstevel@tonic-gate 		/*
37570Sstevel@tonic-gate 		 * Push a module.
37580Sstevel@tonic-gate 		 * For the case __I_PUSH_NOCTTY push a module but
37590Sstevel@tonic-gate 		 * do not allocate controlling tty. See bugid 4025044
37600Sstevel@tonic-gate 		 */
37610Sstevel@tonic-gate 
37625753Sgww 	{
37630Sstevel@tonic-gate 		char mname[FMNAMESZ + 1];
37640Sstevel@tonic-gate 		fmodsw_impl_t *fp;
37650Sstevel@tonic-gate 		dev_t dummydev;
37660Sstevel@tonic-gate 
37670Sstevel@tonic-gate 		if (stp->sd_flag & STRHUP)
37680Sstevel@tonic-gate 			return (ENXIO);
37690Sstevel@tonic-gate 
37700Sstevel@tonic-gate 		/*
37710Sstevel@tonic-gate 		 * Get module name and look up in fmodsw.
37720Sstevel@tonic-gate 		 */
37730Sstevel@tonic-gate 		error = (copyflag & U_TO_K ? copyinstr : copystr)((void *)arg,
37740Sstevel@tonic-gate 		    mname, FMNAMESZ + 1, NULL);
37750Sstevel@tonic-gate 		if (error)
37760Sstevel@tonic-gate 			return ((error == ENAMETOOLONG) ? EINVAL : EFAULT);
37770Sstevel@tonic-gate 
37780Sstevel@tonic-gate 		if ((fp = fmodsw_find(mname, FMODSW_HOLD | FMODSW_LOAD)) ==
37790Sstevel@tonic-gate 		    NULL)
37800Sstevel@tonic-gate 			return (EINVAL);
37810Sstevel@tonic-gate 
37820Sstevel@tonic-gate 		TRACE_2(TR_FAC_STREAMS_FR, TR_I_PUSH,
37830Sstevel@tonic-gate 		    "I_PUSH:fp %p stp %p", fp, stp);
37840Sstevel@tonic-gate 
37850Sstevel@tonic-gate 		if (error = strstartplumb(stp, flag, cmd)) {
37860Sstevel@tonic-gate 			fmodsw_rele(fp);
37870Sstevel@tonic-gate 			return (error);
37880Sstevel@tonic-gate 		}
37890Sstevel@tonic-gate 
37900Sstevel@tonic-gate 		/*
37910Sstevel@tonic-gate 		 * See if any more modules can be pushed on this stream.
37920Sstevel@tonic-gate 		 * Note that this check must be done after strstartplumb()
37930Sstevel@tonic-gate 		 * since otherwise multiple threads issuing I_PUSHes on
37940Sstevel@tonic-gate 		 * the same stream will be able to exceed nstrpush.
37950Sstevel@tonic-gate 		 */
37960Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
37970Sstevel@tonic-gate 		if (stp->sd_pushcnt >= nstrpush) {
37980Sstevel@tonic-gate 			fmodsw_rele(fp);
37990Sstevel@tonic-gate 			strendplumb(stp);
38000Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
38010Sstevel@tonic-gate 			return (EINVAL);
38020Sstevel@tonic-gate 		}
38030Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
38040Sstevel@tonic-gate 
38050Sstevel@tonic-gate 		/*
38060Sstevel@tonic-gate 		 * Push new module and call its open routine
38070Sstevel@tonic-gate 		 * via qattach().  Modules don't change device
38080Sstevel@tonic-gate 		 * numbers, so just ignore dummydev here.
38090Sstevel@tonic-gate 		 */
38100Sstevel@tonic-gate 		dummydev = vp->v_rdev;
38110Sstevel@tonic-gate 		if ((error = qattach(rdq, &dummydev, 0, crp, fp,
38120Sstevel@tonic-gate 		    B_FALSE)) == 0) {
38130Sstevel@tonic-gate 			if (vp->v_type == VCHR && /* sorry, no pipes allowed */
38140Sstevel@tonic-gate 			    (cmd == I_PUSH) && (stp->sd_flag & STRISTTY)) {
38150Sstevel@tonic-gate 				/*
38160Sstevel@tonic-gate 				 * try to allocate it as a controlling terminal
38170Sstevel@tonic-gate 				 */
38182712Snn35248 				(void) strctty(stp);
38190Sstevel@tonic-gate 			}
38200Sstevel@tonic-gate 		}
38210Sstevel@tonic-gate 
38220Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
38230Sstevel@tonic-gate 
38240Sstevel@tonic-gate 		/*
38250Sstevel@tonic-gate 		 * As a performance concern we are caching the values of
38260Sstevel@tonic-gate 		 * q_minpsz and q_maxpsz of the module below the stream
38270Sstevel@tonic-gate 		 * head in the stream head.
38280Sstevel@tonic-gate 		 */
38290Sstevel@tonic-gate 		mutex_enter(QLOCK(stp->sd_wrq->q_next));
38300Sstevel@tonic-gate 		rmin = stp->sd_wrq->q_next->q_minpsz;
38310Sstevel@tonic-gate 		rmax = stp->sd_wrq->q_next->q_maxpsz;
38320Sstevel@tonic-gate 		mutex_exit(QLOCK(stp->sd_wrq->q_next));
38330Sstevel@tonic-gate 
38340Sstevel@tonic-gate 		/* Do this processing here as a performance concern */
38350Sstevel@tonic-gate 		if (strmsgsz != 0) {
38360Sstevel@tonic-gate 			if (rmax == INFPSZ)
38370Sstevel@tonic-gate 				rmax = strmsgsz;
38380Sstevel@tonic-gate 			else  {
38390Sstevel@tonic-gate 				if (vp->v_type == VFIFO)
38400Sstevel@tonic-gate 					rmax = MIN(PIPE_BUF, rmax);
38410Sstevel@tonic-gate 				else	rmax = MIN(strmsgsz, rmax);
38420Sstevel@tonic-gate 			}
38430Sstevel@tonic-gate 		}
38440Sstevel@tonic-gate 
38450Sstevel@tonic-gate 		mutex_enter(QLOCK(wrq));
38460Sstevel@tonic-gate 		stp->sd_qn_minpsz = rmin;
38470Sstevel@tonic-gate 		stp->sd_qn_maxpsz = rmax;
38480Sstevel@tonic-gate 		mutex_exit(QLOCK(wrq));
38490Sstevel@tonic-gate 
38500Sstevel@tonic-gate 		strendplumb(stp);
38510Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
38520Sstevel@tonic-gate 		return (error);
38535753Sgww 	}
38540Sstevel@tonic-gate 
38550Sstevel@tonic-gate 	case I_POP:
38565753Sgww 	{
38570Sstevel@tonic-gate 		queue_t	*q;
38580Sstevel@tonic-gate 
38590Sstevel@tonic-gate 		if (stp->sd_flag & STRHUP)
38600Sstevel@tonic-gate 			return (ENXIO);
38610Sstevel@tonic-gate 		if (!wrq->q_next)	/* for broken pipes */
38620Sstevel@tonic-gate 			return (EINVAL);
38630Sstevel@tonic-gate 
38640Sstevel@tonic-gate 		if (error = strstartplumb(stp, flag, cmd))
38650Sstevel@tonic-gate 			return (error);
38660Sstevel@tonic-gate 
38670Sstevel@tonic-gate 		/*
38680Sstevel@tonic-gate 		 * If there is an anchor on this stream and popping
38690Sstevel@tonic-gate 		 * the current module would attempt to pop through the
38700Sstevel@tonic-gate 		 * anchor, then disallow the pop unless we have sufficient
38710Sstevel@tonic-gate 		 * privileges; take the cheapest (non-locking) check
38720Sstevel@tonic-gate 		 * first.
38730Sstevel@tonic-gate 		 */
38743448Sdh155122 		if (secpolicy_ip_config(crp, B_TRUE) != 0 ||
38753448Sdh155122 		    (stp->sd_anchorzone != crgetzoneid(crp))) {
38760Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
38770Sstevel@tonic-gate 			/*
38780Sstevel@tonic-gate 			 * Anchors only apply if there's at least one
38790Sstevel@tonic-gate 			 * module on the stream (sd_pushcnt > 0).
38800Sstevel@tonic-gate 			 */
38810Sstevel@tonic-gate 			if (stp->sd_pushcnt > 0 &&
38820Sstevel@tonic-gate 			    stp->sd_pushcnt == stp->sd_anchor &&
38830Sstevel@tonic-gate 			    stp->sd_vnode->v_type != VFIFO) {
38840Sstevel@tonic-gate 				strendplumb(stp);
38850Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
38863448Sdh155122 				if (stp->sd_anchorzone != crgetzoneid(crp))
38873448Sdh155122 					return (EINVAL);
38880Sstevel@tonic-gate 				/* Audit and report error */
38893448Sdh155122 				return (secpolicy_ip_config(crp, B_FALSE));
38900Sstevel@tonic-gate 			}
38910Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
38920Sstevel@tonic-gate 		}
38930Sstevel@tonic-gate 
38940Sstevel@tonic-gate 		q = wrq->q_next;
38950Sstevel@tonic-gate 		TRACE_2(TR_FAC_STREAMS_FR, TR_I_POP,
38965753Sgww 		    "I_POP:%p from %p", q, stp);
38970Sstevel@tonic-gate 		if (q->q_next == NULL || (q->q_flag & (QREADR|QISDRV))) {
38980Sstevel@tonic-gate 			error = EINVAL;
38990Sstevel@tonic-gate 		} else {
39000Sstevel@tonic-gate 			qdetach(_RD(q), 1, flag, crp, B_FALSE);
39010Sstevel@tonic-gate 			error = 0;
39020Sstevel@tonic-gate 		}
39030Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
39040Sstevel@tonic-gate 
39050Sstevel@tonic-gate 		/*
39060Sstevel@tonic-gate 		 * As a performance concern we are caching the values of
39070Sstevel@tonic-gate 		 * q_minpsz and q_maxpsz of the module below the stream
39080Sstevel@tonic-gate 		 * head in the stream head.
39090Sstevel@tonic-gate 		 */
39100Sstevel@tonic-gate 		mutex_enter(QLOCK(wrq->q_next));
39110Sstevel@tonic-gate 		rmin = wrq->q_next->q_minpsz;
39120Sstevel@tonic-gate 		rmax = wrq->q_next->q_maxpsz;
39130Sstevel@tonic-gate 		mutex_exit(QLOCK(wrq->q_next));
39140Sstevel@tonic-gate 
39150Sstevel@tonic-gate 		/* Do this processing here as a performance concern */
39160Sstevel@tonic-gate 		if (strmsgsz != 0) {
39170Sstevel@tonic-gate 			if (rmax == INFPSZ)
39180Sstevel@tonic-gate 				rmax = strmsgsz;
39190Sstevel@tonic-gate 			else  {
39200Sstevel@tonic-gate 				if (vp->v_type == VFIFO)
39210Sstevel@tonic-gate 					rmax = MIN(PIPE_BUF, rmax);
39220Sstevel@tonic-gate 				else	rmax = MIN(strmsgsz, rmax);
39230Sstevel@tonic-gate 			}
39240Sstevel@tonic-gate 		}
39250Sstevel@tonic-gate 
39260Sstevel@tonic-gate 		mutex_enter(QLOCK(wrq));
39270Sstevel@tonic-gate 		stp->sd_qn_minpsz = rmin;
39280Sstevel@tonic-gate 		stp->sd_qn_maxpsz = rmax;
39290Sstevel@tonic-gate 		mutex_exit(QLOCK(wrq));
39300Sstevel@tonic-gate 
39310Sstevel@tonic-gate 		/* If we popped through the anchor, then reset the anchor. */
39323448Sdh155122 		if (stp->sd_pushcnt < stp->sd_anchor) {
39330Sstevel@tonic-gate 			stp->sd_anchor = 0;
39343448Sdh155122 			stp->sd_anchorzone = 0;
39353448Sdh155122 		}
39360Sstevel@tonic-gate 		strendplumb(stp);
39370Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
39380Sstevel@tonic-gate 		return (error);
39395753Sgww 	}
39400Sstevel@tonic-gate 
39410Sstevel@tonic-gate 	case _I_MUXID2FD:
39420Sstevel@tonic-gate 	{
39430Sstevel@tonic-gate 		/*
39440Sstevel@tonic-gate 		 * Create a fd for a I_PLINK'ed lower stream with a given
39450Sstevel@tonic-gate 		 * muxid.  With the fd, application can send down ioctls,
39460Sstevel@tonic-gate 		 * like I_LIST, to the previously I_PLINK'ed stream.  Note
39470Sstevel@tonic-gate 		 * that after getting the fd, the application has to do an
39480Sstevel@tonic-gate 		 * I_PUNLINK on the muxid before it can do any operation
39490Sstevel@tonic-gate 		 * on the lower stream.  This is required by spec1170.
39500Sstevel@tonic-gate 		 *
39510Sstevel@tonic-gate 		 * The fd used to do this ioctl should point to the same
39520Sstevel@tonic-gate 		 * controlling device used to do the I_PLINK.  If it uses
39530Sstevel@tonic-gate 		 * a different stream or an invalid muxid, I_MUXID2FD will
39540Sstevel@tonic-gate 		 * fail.  The error code is set to EINVAL.
39550Sstevel@tonic-gate 		 *
39560Sstevel@tonic-gate 		 * The intended use of this interface is the following.
39570Sstevel@tonic-gate 		 * An application I_PLINK'ed a stream and exits.  The fd
39580Sstevel@tonic-gate 		 * to the lower stream is gone.  Another application
39590Sstevel@tonic-gate 		 * wants to get a fd to the lower stream, it uses I_MUXID2FD.
39600Sstevel@tonic-gate 		 */
39610Sstevel@tonic-gate 		int muxid = (int)arg;
39620Sstevel@tonic-gate 		int fd;
39630Sstevel@tonic-gate 		linkinfo_t *linkp;
39640Sstevel@tonic-gate 		struct file *fp;
39653448Sdh155122 		netstack_t *ns;
39663448Sdh155122 		str_stack_t *ss;
39670Sstevel@tonic-gate 
39680Sstevel@tonic-gate 		/*
39690Sstevel@tonic-gate 		 * Do not allow the wildcard muxid.  This ioctl is not
39700Sstevel@tonic-gate 		 * intended to find arbitrary link.
39710Sstevel@tonic-gate 		 */
39720Sstevel@tonic-gate 		if (muxid == 0) {
39730Sstevel@tonic-gate 			return (EINVAL);
39740Sstevel@tonic-gate 		}
39750Sstevel@tonic-gate 
39763448Sdh155122 		ns = netstack_find_by_cred(crp);
39773448Sdh155122 		ASSERT(ns != NULL);
39783448Sdh155122 		ss = ns->netstack_str;
39793448Sdh155122 		ASSERT(ss != NULL);
39803448Sdh155122 
39810Sstevel@tonic-gate 		mutex_enter(&muxifier);
39823448Sdh155122 		linkp = findlinks(vp->v_stream, muxid, LINKPERSIST, ss);
39830Sstevel@tonic-gate 		if (linkp == NULL) {
39840Sstevel@tonic-gate 			mutex_exit(&muxifier);
39853448Sdh155122 			netstack_rele(ss->ss_netstack);
39860Sstevel@tonic-gate 			return (EINVAL);
39870Sstevel@tonic-gate 		}
39880Sstevel@tonic-gate 
39890Sstevel@tonic-gate 		if ((fd = ufalloc(0)) == -1) {
39900Sstevel@tonic-gate 			mutex_exit(&muxifier);
39913448Sdh155122 			netstack_rele(ss->ss_netstack);
39920Sstevel@tonic-gate 			return (EMFILE);
39930Sstevel@tonic-gate 		}
39940Sstevel@tonic-gate 		fp = linkp->li_fpdown;
39950Sstevel@tonic-gate 		mutex_enter(&fp->f_tlock);
39960Sstevel@tonic-gate 		fp->f_count++;
39970Sstevel@tonic-gate 		mutex_exit(&fp->f_tlock);
39980Sstevel@tonic-gate 		mutex_exit(&muxifier);
39990Sstevel@tonic-gate 		setf(fd, fp);
40000Sstevel@tonic-gate 		*rvalp = fd;
40013448Sdh155122 		netstack_rele(ss->ss_netstack);
40020Sstevel@tonic-gate 		return (0);
40030Sstevel@tonic-gate 	}
40040Sstevel@tonic-gate 
40050Sstevel@tonic-gate 	case _I_INSERT:
40060Sstevel@tonic-gate 	{
40070Sstevel@tonic-gate 		/*
40080Sstevel@tonic-gate 		 * To insert a module to a given position in a stream.
40090Sstevel@tonic-gate 		 * In the first release, only allow privileged user
40103448Sdh155122 		 * to use this ioctl. Furthermore, the insert is only allowed
40113448Sdh155122 		 * below an anchor if the zoneid is the same as the zoneid
40123448Sdh155122 		 * which created the anchor.
40130Sstevel@tonic-gate 		 *
40140Sstevel@tonic-gate 		 * Note that we do not plan to support this ioctl
40150Sstevel@tonic-gate 		 * on pipes in the first release.  We want to learn more
40160Sstevel@tonic-gate 		 * about the implications of these ioctls before extending
40170Sstevel@tonic-gate 		 * their support.  And we do not think these features are
40180Sstevel@tonic-gate 		 * valuable for pipes.
40190Sstevel@tonic-gate 		 */
40200Sstevel@tonic-gate 		STRUCT_DECL(strmodconf, strmodinsert);
40210Sstevel@tonic-gate 		char mod_name[FMNAMESZ + 1];
40220Sstevel@tonic-gate 		fmodsw_impl_t *fp;
40230Sstevel@tonic-gate 		dev_t dummydev;
40240Sstevel@tonic-gate 		queue_t *tmp_wrq;
40250Sstevel@tonic-gate 		int pos;
40260Sstevel@tonic-gate 		boolean_t is_insert;
40270Sstevel@tonic-gate 
40280Sstevel@tonic-gate 		STRUCT_INIT(strmodinsert, flag);
40290Sstevel@tonic-gate 		if (stp->sd_flag & STRHUP)
40300Sstevel@tonic-gate 			return (ENXIO);
40310Sstevel@tonic-gate 		if (STRMATED(stp))
40320Sstevel@tonic-gate 			return (EINVAL);
40330Sstevel@tonic-gate 		if ((error = secpolicy_net_config(crp, B_FALSE)) != 0)
40340Sstevel@tonic-gate 			return (error);
40353448Sdh155122 		if (stp->sd_anchor != 0 &&
40363448Sdh155122 		    stp->sd_anchorzone != crgetzoneid(crp))
40373448Sdh155122 			return (EINVAL);
40380Sstevel@tonic-gate 
40390Sstevel@tonic-gate 		error = strcopyin((void *)arg, STRUCT_BUF(strmodinsert),
40400Sstevel@tonic-gate 		    STRUCT_SIZE(strmodinsert), copyflag);
40410Sstevel@tonic-gate 		if (error)
40420Sstevel@tonic-gate 			return (error);
40430Sstevel@tonic-gate 
40440Sstevel@tonic-gate 		/*
40450Sstevel@tonic-gate 		 * Get module name and look up in fmodsw.
40460Sstevel@tonic-gate 		 */
40470Sstevel@tonic-gate 		error = (copyflag & U_TO_K ? copyinstr :
40480Sstevel@tonic-gate 		    copystr)(STRUCT_FGETP(strmodinsert, mod_name),
40490Sstevel@tonic-gate 		    mod_name, FMNAMESZ + 1, NULL);
40500Sstevel@tonic-gate 		if (error)
40510Sstevel@tonic-gate 			return ((error == ENAMETOOLONG) ? EINVAL : EFAULT);
40520Sstevel@tonic-gate 
40530Sstevel@tonic-gate 		if ((fp = fmodsw_find(mod_name, FMODSW_HOLD | FMODSW_LOAD)) ==
40540Sstevel@tonic-gate 		    NULL)
40550Sstevel@tonic-gate 			return (EINVAL);
40560Sstevel@tonic-gate 
40570Sstevel@tonic-gate 		if (error = strstartplumb(stp, flag, cmd)) {
40580Sstevel@tonic-gate 			fmodsw_rele(fp);
40590Sstevel@tonic-gate 			return (error);
40600Sstevel@tonic-gate 		}
40610Sstevel@tonic-gate 
40620Sstevel@tonic-gate 		/*
40630Sstevel@tonic-gate 		 * Is this _I_INSERT just like an I_PUSH?  We need to know
40640Sstevel@tonic-gate 		 * this because we do some optimizations if this is a
40650Sstevel@tonic-gate 		 * module being pushed.
40660Sstevel@tonic-gate 		 */
40670Sstevel@tonic-gate 		pos = STRUCT_FGET(strmodinsert, pos);
40680Sstevel@tonic-gate 		is_insert = (pos != 0);
40690Sstevel@tonic-gate 
40700Sstevel@tonic-gate 		/*
40710Sstevel@tonic-gate 		 * Make sure pos is valid.  Even though it is not an I_PUSH,
40720Sstevel@tonic-gate 		 * we impose the same limit on the number of modules in a
40730Sstevel@tonic-gate 		 * stream.
40740Sstevel@tonic-gate 		 */
40750Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
40760Sstevel@tonic-gate 		if (stp->sd_pushcnt >= nstrpush || pos < 0 ||
40770Sstevel@tonic-gate 		    pos > stp->sd_pushcnt) {
40780Sstevel@tonic-gate 			fmodsw_rele(fp);
40790Sstevel@tonic-gate 			strendplumb(stp);
40800Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
40810Sstevel@tonic-gate 			return (EINVAL);
40820Sstevel@tonic-gate 		}
40833448Sdh155122 		if (stp->sd_anchor != 0) {
40843448Sdh155122 			/*
40853448Sdh155122 			 * Is this insert below the anchor?
40863448Sdh155122 			 * Pushcnt hasn't been increased yet hence
40873448Sdh155122 			 * we test for greater than here, and greater or
40883448Sdh155122 			 * equal after qattach.
40893448Sdh155122 			 */
40903448Sdh155122 			if (pos > (stp->sd_pushcnt - stp->sd_anchor) &&
40913448Sdh155122 			    stp->sd_anchorzone != crgetzoneid(crp)) {
40923448Sdh155122 				fmodsw_rele(fp);
40933448Sdh155122 				strendplumb(stp);
40943448Sdh155122 				mutex_exit(&stp->sd_lock);
40953448Sdh155122 				return (EPERM);
40963448Sdh155122 			}
40973448Sdh155122 		}
40983448Sdh155122 
40990Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
41000Sstevel@tonic-gate 
41010Sstevel@tonic-gate 		/*
41020Sstevel@tonic-gate 		 * First find the correct position this module to
41030Sstevel@tonic-gate 		 * be inserted.  We don't need to call claimstr()
41040Sstevel@tonic-gate 		 * as the stream should not be changing at this point.
41050Sstevel@tonic-gate 		 *
41060Sstevel@tonic-gate 		 * Insert new module and call its open routine
41070Sstevel@tonic-gate 		 * via qattach().  Modules don't change device
41080Sstevel@tonic-gate 		 * numbers, so just ignore dummydev here.
41090Sstevel@tonic-gate 		 */
41100Sstevel@tonic-gate 		for (tmp_wrq = stp->sd_wrq; pos > 0;
41110Sstevel@tonic-gate 		    tmp_wrq = tmp_wrq->q_next, pos--) {
41120Sstevel@tonic-gate 			ASSERT(SAMESTR(tmp_wrq));
41130Sstevel@tonic-gate 		}
41140Sstevel@tonic-gate 		dummydev = vp->v_rdev;
41150Sstevel@tonic-gate 		if ((error = qattach(_RD(tmp_wrq), &dummydev, 0, crp,
41160Sstevel@tonic-gate 		    fp, is_insert)) != 0) {
41170Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
41180Sstevel@tonic-gate 			strendplumb(stp);
41190Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
41200Sstevel@tonic-gate 			return (error);
41210Sstevel@tonic-gate 		}
41220Sstevel@tonic-gate 
41230Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
41240Sstevel@tonic-gate 
41250Sstevel@tonic-gate 		/*
41260Sstevel@tonic-gate 		 * As a performance concern we are caching the values of
41270Sstevel@tonic-gate 		 * q_minpsz and q_maxpsz of the module below the stream
41280Sstevel@tonic-gate 		 * head in the stream head.
41290Sstevel@tonic-gate 		 */
41300Sstevel@tonic-gate 		if (!is_insert) {
41310Sstevel@tonic-gate 			mutex_enter(QLOCK(stp->sd_wrq->q_next));
41320Sstevel@tonic-gate 			rmin = stp->sd_wrq->q_next->q_minpsz;
41330Sstevel@tonic-gate 			rmax = stp->sd_wrq->q_next->q_maxpsz;
41340Sstevel@tonic-gate 			mutex_exit(QLOCK(stp->sd_wrq->q_next));
41350Sstevel@tonic-gate 
41360Sstevel@tonic-gate 			/* Do this processing here as a performance concern */
41370Sstevel@tonic-gate 			if (strmsgsz != 0) {
41380Sstevel@tonic-gate 				if (rmax == INFPSZ) {
41390Sstevel@tonic-gate 					rmax = strmsgsz;
41400Sstevel@tonic-gate 				} else  {
41410Sstevel@tonic-gate 					rmax = MIN(strmsgsz, rmax);
41420Sstevel@tonic-gate 				}
41430Sstevel@tonic-gate 			}
41440Sstevel@tonic-gate 
41450Sstevel@tonic-gate 			mutex_enter(QLOCK(wrq));
41460Sstevel@tonic-gate 			stp->sd_qn_minpsz = rmin;
41470Sstevel@tonic-gate 			stp->sd_qn_maxpsz = rmax;
41480Sstevel@tonic-gate 			mutex_exit(QLOCK(wrq));
41490Sstevel@tonic-gate 		}
41500Sstevel@tonic-gate 
41510Sstevel@tonic-gate 		/*
41520Sstevel@tonic-gate 		 * Need to update the anchor value if this module is
41530Sstevel@tonic-gate 		 * inserted below the anchor point.
41540Sstevel@tonic-gate 		 */
41550Sstevel@tonic-gate 		if (stp->sd_anchor != 0) {
41560Sstevel@tonic-gate 			pos = STRUCT_FGET(strmodinsert, pos);
41570Sstevel@tonic-gate 			if (pos >= (stp->sd_pushcnt - stp->sd_anchor))
41580Sstevel@tonic-gate 				stp->sd_anchor++;
41590Sstevel@tonic-gate 		}
41600Sstevel@tonic-gate 
41610Sstevel@tonic-gate 		strendplumb(stp);
41620Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
41630Sstevel@tonic-gate 		return (0);
41640Sstevel@tonic-gate 	}
41650Sstevel@tonic-gate 
41660Sstevel@tonic-gate 	case _I_REMOVE:
41670Sstevel@tonic-gate 	{
41680Sstevel@tonic-gate 		/*
41690Sstevel@tonic-gate 		 * To remove a module with a given name in a stream.  The
41700Sstevel@tonic-gate 		 * caller of this ioctl needs to provide both the name and
41710Sstevel@tonic-gate 		 * the position of the module to be removed.  This eliminates
41720Sstevel@tonic-gate 		 * the ambiguity of removal if a module is inserted/pushed
41730Sstevel@tonic-gate 		 * multiple times in a stream.  In the first release, only
41740Sstevel@tonic-gate 		 * allow privileged user to use this ioctl.
41753448Sdh155122 		 * Furthermore, the remove is only allowed
41763448Sdh155122 		 * below an anchor if the zoneid is the same as the zoneid
41773448Sdh155122 		 * which created the anchor.
41780Sstevel@tonic-gate 		 *
41790Sstevel@tonic-gate 		 * Note that we do not plan to support this ioctl
41800Sstevel@tonic-gate 		 * on pipes in the first release.  We want to learn more
41810Sstevel@tonic-gate 		 * about the implications of these ioctls before extending
41820Sstevel@tonic-gate 		 * their support.  And we do not think these features are
41830Sstevel@tonic-gate 		 * valuable for pipes.
41840Sstevel@tonic-gate 		 *
41850Sstevel@tonic-gate 		 * Also note that _I_REMOVE cannot be used to remove a
41860Sstevel@tonic-gate 		 * driver or the stream head.
41870Sstevel@tonic-gate 		 */
41880Sstevel@tonic-gate 		STRUCT_DECL(strmodconf, strmodremove);
41890Sstevel@tonic-gate 		queue_t	*q;
41900Sstevel@tonic-gate 		int pos;
41910Sstevel@tonic-gate 		char mod_name[FMNAMESZ + 1];
41920Sstevel@tonic-gate 		boolean_t is_remove;
41930Sstevel@tonic-gate 
41940Sstevel@tonic-gate 		STRUCT_INIT(strmodremove, flag);
41950Sstevel@tonic-gate 		if (stp->sd_flag & STRHUP)
41960Sstevel@tonic-gate 			return (ENXIO);
41970Sstevel@tonic-gate 		if (STRMATED(stp))
41980Sstevel@tonic-gate 			return (EINVAL);
41990Sstevel@tonic-gate 		if ((error = secpolicy_net_config(crp, B_FALSE)) != 0)
42000Sstevel@tonic-gate 			return (error);
42013448Sdh155122 		if (stp->sd_anchor != 0 &&
42023448Sdh155122 		    stp->sd_anchorzone != crgetzoneid(crp))
42033448Sdh155122 			return (EINVAL);
42040Sstevel@tonic-gate 
42050Sstevel@tonic-gate 		error = strcopyin((void *)arg, STRUCT_BUF(strmodremove),
42060Sstevel@tonic-gate 		    STRUCT_SIZE(strmodremove), copyflag);
42070Sstevel@tonic-gate 		if (error)
42080Sstevel@tonic-gate 			return (error);
42090Sstevel@tonic-gate 
42100Sstevel@tonic-gate 		error = (copyflag & U_TO_K ? copyinstr :
42110Sstevel@tonic-gate 		    copystr)(STRUCT_FGETP(strmodremove, mod_name),
42120Sstevel@tonic-gate 		    mod_name, FMNAMESZ + 1, NULL);
42130Sstevel@tonic-gate 		if (error)
42140Sstevel@tonic-gate 			return ((error == ENAMETOOLONG) ? EINVAL : EFAULT);
42150Sstevel@tonic-gate 
42160Sstevel@tonic-gate 		if ((error = strstartplumb(stp, flag, cmd)) != 0)
42170Sstevel@tonic-gate 			return (error);
42180Sstevel@tonic-gate 
42190Sstevel@tonic-gate 		/*
42200Sstevel@tonic-gate 		 * Match the name of given module to the name of module at
42210Sstevel@tonic-gate 		 * the given position.
42220Sstevel@tonic-gate 		 */
42230Sstevel@tonic-gate 		pos = STRUCT_FGET(strmodremove, pos);
42240Sstevel@tonic-gate 
42250Sstevel@tonic-gate 		is_remove = (pos != 0);
42260Sstevel@tonic-gate 		for (q = stp->sd_wrq->q_next; SAMESTR(q) && pos > 0;
42270Sstevel@tonic-gate 		    q = q->q_next, pos--)
42280Sstevel@tonic-gate 			;
42298752SPeter.Memishian@Sun.COM 		if (pos > 0 || !SAMESTR(q) ||
42308752SPeter.Memishian@Sun.COM 		    strcmp(Q2NAME(q), mod_name) != 0) {
42310Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
42320Sstevel@tonic-gate 			strendplumb(stp);
42330Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
42340Sstevel@tonic-gate 			return (EINVAL);
42350Sstevel@tonic-gate 		}
42360Sstevel@tonic-gate 
42373448Sdh155122 		/*
42383448Sdh155122 		 * If the position is at or below an anchor, then the zoneid
42393448Sdh155122 		 * must match the zoneid that created the anchor.
42403448Sdh155122 		 */
42413448Sdh155122 		if (stp->sd_anchor != 0) {
42423448Sdh155122 			pos = STRUCT_FGET(strmodremove, pos);
42433448Sdh155122 			if (pos >= (stp->sd_pushcnt - stp->sd_anchor) &&
42443448Sdh155122 			    stp->sd_anchorzone != crgetzoneid(crp)) {
42453448Sdh155122 				mutex_enter(&stp->sd_lock);
42463448Sdh155122 				strendplumb(stp);
42473448Sdh155122 				mutex_exit(&stp->sd_lock);
42483448Sdh155122 				return (EPERM);
42493448Sdh155122 			}
42503448Sdh155122 		}
42513448Sdh155122 
42523448Sdh155122 
42530Sstevel@tonic-gate 		ASSERT(!(q->q_flag & QREADR));
42540Sstevel@tonic-gate 		qdetach(_RD(q), 1, flag, crp, is_remove);
42550Sstevel@tonic-gate 
42560Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
42570Sstevel@tonic-gate 
42580Sstevel@tonic-gate 		/*
42590Sstevel@tonic-gate 		 * As a performance concern we are caching the values of
42600Sstevel@tonic-gate 		 * q_minpsz and q_maxpsz of the module below the stream
42610Sstevel@tonic-gate 		 * head in the stream head.
42620Sstevel@tonic-gate 		 */
42630Sstevel@tonic-gate 		if (!is_remove) {
42640Sstevel@tonic-gate 			mutex_enter(QLOCK(wrq->q_next));
42650Sstevel@tonic-gate 			rmin = wrq->q_next->q_minpsz;
42660Sstevel@tonic-gate 			rmax = wrq->q_next->q_maxpsz;
42670Sstevel@tonic-gate 			mutex_exit(QLOCK(wrq->q_next));
42680Sstevel@tonic-gate 
42690Sstevel@tonic-gate 			/* Do this processing here as a performance concern */
42700Sstevel@tonic-gate 			if (strmsgsz != 0) {
42710Sstevel@tonic-gate 				if (rmax == INFPSZ)
42720Sstevel@tonic-gate 					rmax = strmsgsz;
42730Sstevel@tonic-gate 				else  {
42740Sstevel@tonic-gate 					if (vp->v_type == VFIFO)
42750Sstevel@tonic-gate 						rmax = MIN(PIPE_BUF, rmax);
42760Sstevel@tonic-gate 					else	rmax = MIN(strmsgsz, rmax);
42770Sstevel@tonic-gate 				}
42780Sstevel@tonic-gate 			}
42790Sstevel@tonic-gate 
42800Sstevel@tonic-gate 			mutex_enter(QLOCK(wrq));
42810Sstevel@tonic-gate 			stp->sd_qn_minpsz = rmin;
42820Sstevel@tonic-gate 			stp->sd_qn_maxpsz = rmax;
42830Sstevel@tonic-gate 			mutex_exit(QLOCK(wrq));
42840Sstevel@tonic-gate 		}
42850Sstevel@tonic-gate 
42860Sstevel@tonic-gate 		/*
42870Sstevel@tonic-gate 		 * Need to update the anchor value if this module is removed
42880Sstevel@tonic-gate 		 * at or below the anchor point.  If the removed module is at
42890Sstevel@tonic-gate 		 * the anchor point, remove the anchor for this stream if
42900Sstevel@tonic-gate 		 * there is no module above the anchor point.  Otherwise, if
42910Sstevel@tonic-gate 		 * the removed module is below the anchor point, decrement the
42920Sstevel@tonic-gate 		 * anchor point by 1.
42930Sstevel@tonic-gate 		 */
42940Sstevel@tonic-gate 		if (stp->sd_anchor != 0) {
42950Sstevel@tonic-gate 			pos = STRUCT_FGET(strmodremove, pos);
42963448Sdh155122 			if (pos == stp->sd_pushcnt - stp->sd_anchor + 1)
42970Sstevel@tonic-gate 				stp->sd_anchor = 0;
42980Sstevel@tonic-gate 			else if (pos > (stp->sd_pushcnt - stp->sd_anchor + 1))
42990Sstevel@tonic-gate 				stp->sd_anchor--;
43000Sstevel@tonic-gate 		}
43010Sstevel@tonic-gate 
43020Sstevel@tonic-gate 		strendplumb(stp);
43030Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
43040Sstevel@tonic-gate 		return (0);
43050Sstevel@tonic-gate 	}
43060Sstevel@tonic-gate 
43070Sstevel@tonic-gate 	case I_ANCHOR:
43080Sstevel@tonic-gate 		/*
43090Sstevel@tonic-gate 		 * Set the anchor position on the stream to reside at
43100Sstevel@tonic-gate 		 * the top module (in other words, the top module
43110Sstevel@tonic-gate 		 * cannot be popped).  Anchors with a FIFO make no
43120Sstevel@tonic-gate 		 * obvious sense, so they're not allowed.
43130Sstevel@tonic-gate 		 */
43140Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
43150Sstevel@tonic-gate 
43160Sstevel@tonic-gate 		if (stp->sd_vnode->v_type == VFIFO) {
43170Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
43180Sstevel@tonic-gate 			return (EINVAL);
43190Sstevel@tonic-gate 		}
43203448Sdh155122 		/* Only allow the same zoneid to update the anchor */
43213448Sdh155122 		if (stp->sd_anchor != 0 &&
43223448Sdh155122 		    stp->sd_anchorzone != crgetzoneid(crp)) {
43233448Sdh155122 			mutex_exit(&stp->sd_lock);
43243448Sdh155122 			return (EINVAL);
43253448Sdh155122 		}
43260Sstevel@tonic-gate 		stp->sd_anchor = stp->sd_pushcnt;
43273448Sdh155122 		stp->sd_anchorzone = crgetzoneid(crp);
43280Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
43290Sstevel@tonic-gate 		return (0);
43300Sstevel@tonic-gate 
43310Sstevel@tonic-gate 	case I_LOOK:
43320Sstevel@tonic-gate 		/*
43330Sstevel@tonic-gate 		 * Get name of first module downstream.
43340Sstevel@tonic-gate 		 * If no module, return an error.
43350Sstevel@tonic-gate 		 */
43360Sstevel@tonic-gate 		claimstr(wrq);
43378752SPeter.Memishian@Sun.COM 		if (_SAMESTR(wrq) && wrq->q_next->q_next != NULL) {
43388752SPeter.Memishian@Sun.COM 			char *name = Q2NAME(wrq->q_next);
43398752SPeter.Memishian@Sun.COM 
43400Sstevel@tonic-gate 			error = strcopyout(name, (void *)arg, strlen(name) + 1,
43410Sstevel@tonic-gate 			    copyflag);
43420Sstevel@tonic-gate 			releasestr(wrq);
43430Sstevel@tonic-gate 			return (error);
43440Sstevel@tonic-gate 		}
43450Sstevel@tonic-gate 		releasestr(wrq);
43460Sstevel@tonic-gate 		return (EINVAL);
43470Sstevel@tonic-gate 
43480Sstevel@tonic-gate 	case I_LINK:
43490Sstevel@tonic-gate 	case I_PLINK:
43500Sstevel@tonic-gate 		/*
43510Sstevel@tonic-gate 		 * Link a multiplexor.
43520Sstevel@tonic-gate 		 */
43538752SPeter.Memishian@Sun.COM 		return (mlink(vp, cmd, (int)arg, crp, rvalp, 0));
43540Sstevel@tonic-gate 
43550Sstevel@tonic-gate 	case _I_PLINK_LH:
43560Sstevel@tonic-gate 		/*
43570Sstevel@tonic-gate 		 * Link a multiplexor: Call must originate from kernel.
43580Sstevel@tonic-gate 		 */
43590Sstevel@tonic-gate 		if (kioctl)
43600Sstevel@tonic-gate 			return (ldi_mlink_lh(vp, cmd, arg, crp, rvalp));
43610Sstevel@tonic-gate 
43620Sstevel@tonic-gate 		return (EINVAL);
43630Sstevel@tonic-gate 	case I_UNLINK:
43640Sstevel@tonic-gate 	case I_PUNLINK:
43650Sstevel@tonic-gate 		/*
43660Sstevel@tonic-gate 		 * Unlink a multiplexor.
43670Sstevel@tonic-gate 		 * If arg is -1, unlink all links for which this is the
43680Sstevel@tonic-gate 		 * controlling stream.  Otherwise, arg is an index number
43690Sstevel@tonic-gate 		 * for a link to be removed.
43700Sstevel@tonic-gate 		 */
43715753Sgww 	{
43720Sstevel@tonic-gate 		struct linkinfo *linkp;
43730Sstevel@tonic-gate 		int native_arg = (int)arg;
43740Sstevel@tonic-gate 		int type;
43753448Sdh155122 		netstack_t *ns;
43763448Sdh155122 		str_stack_t *ss;
43770Sstevel@tonic-gate 
43780Sstevel@tonic-gate 		TRACE_1(TR_FAC_STREAMS_FR,
43795753Sgww 		    TR_I_UNLINK, "I_UNLINK/I_PUNLINK:%p", stp);
43800Sstevel@tonic-gate 		if (vp->v_type == VFIFO) {
43810Sstevel@tonic-gate 			return (EINVAL);
43820Sstevel@tonic-gate 		}
43830Sstevel@tonic-gate 		if (cmd == I_UNLINK)
43840Sstevel@tonic-gate 			type = LINKNORMAL;
43850Sstevel@tonic-gate 		else	/* I_PUNLINK */
43860Sstevel@tonic-gate 			type = LINKPERSIST;
43870Sstevel@tonic-gate 		if (native_arg == 0) {
43880Sstevel@tonic-gate 			return (EINVAL);
43890Sstevel@tonic-gate 		}
43903448Sdh155122 		ns = netstack_find_by_cred(crp);
43913448Sdh155122 		ASSERT(ns != NULL);
43923448Sdh155122 		ss = ns->netstack_str;
43933448Sdh155122 		ASSERT(ss != NULL);
43943448Sdh155122 
43950Sstevel@tonic-gate 		if (native_arg == MUXID_ALL)
43963448Sdh155122 			error = munlinkall(stp, type, crp, rvalp, ss);
43970Sstevel@tonic-gate 		else {
43980Sstevel@tonic-gate 			mutex_enter(&muxifier);
43993448Sdh155122 			if (!(linkp = findlinks(stp, (int)arg, type, ss))) {
44000Sstevel@tonic-gate 				/* invalid user supplied index number */
44010Sstevel@tonic-gate 				mutex_exit(&muxifier);
44023448Sdh155122 				netstack_rele(ss->ss_netstack);
44030Sstevel@tonic-gate 				return (EINVAL);
44040Sstevel@tonic-gate 			}
44050Sstevel@tonic-gate 			/* munlink drops the muxifier lock */
44063448Sdh155122 			error = munlink(stp, linkp, type, crp, rvalp, ss);
44073448Sdh155122 		}
44083448Sdh155122 		netstack_rele(ss->ss_netstack);
44090Sstevel@tonic-gate 		return (error);
44105753Sgww 	}
44110Sstevel@tonic-gate 
44120Sstevel@tonic-gate 	case I_FLUSH:
44130Sstevel@tonic-gate 		/*
44140Sstevel@tonic-gate 		 * send a flush message downstream
44150Sstevel@tonic-gate 		 * flush message can indicate
44160Sstevel@tonic-gate 		 * FLUSHR - flush read queue
44170Sstevel@tonic-gate 		 * FLUSHW - flush write queue
44180Sstevel@tonic-gate 		 * FLUSHRW - flush read/write queue
44190Sstevel@tonic-gate 		 */
44200Sstevel@tonic-gate 		if (stp->sd_flag & STRHUP)
44210Sstevel@tonic-gate 			return (ENXIO);
44220Sstevel@tonic-gate 		if (arg & ~FLUSHRW)
44230Sstevel@tonic-gate 			return (EINVAL);
44240Sstevel@tonic-gate 
44250Sstevel@tonic-gate 		for (;;) {
44260Sstevel@tonic-gate 			if (putnextctl1(stp->sd_wrq, M_FLUSH, (int)arg)) {
44270Sstevel@tonic-gate 				break;
44280Sstevel@tonic-gate 			}
44290Sstevel@tonic-gate 			if (error = strwaitbuf(1, BPRI_HI)) {
44300Sstevel@tonic-gate 				return (error);
44310Sstevel@tonic-gate 			}
44320Sstevel@tonic-gate 		}
44330Sstevel@tonic-gate 
44340Sstevel@tonic-gate 		/*
44350Sstevel@tonic-gate 		 * Send down an unsupported ioctl and wait for the nack
44360Sstevel@tonic-gate 		 * in order to allow the M_FLUSH to propagate back
44370Sstevel@tonic-gate 		 * up to the stream head.
44380Sstevel@tonic-gate 		 * Replaces if (qready()) runqueues();
44390Sstevel@tonic-gate 		 */
44400Sstevel@tonic-gate 		strioc.ic_cmd = -1;	/* The unsupported ioctl */
44410Sstevel@tonic-gate 		strioc.ic_timout = 0;
44420Sstevel@tonic-gate 		strioc.ic_len = 0;
44430Sstevel@tonic-gate 		strioc.ic_dp = NULL;
44440Sstevel@tonic-gate 		(void) strdoioctl(stp, &strioc, flag, K_TO_K, crp, rvalp);
44450Sstevel@tonic-gate 		*rvalp = 0;
44460Sstevel@tonic-gate 		return (0);
44470Sstevel@tonic-gate 
44480Sstevel@tonic-gate 	case I_FLUSHBAND:
44495753Sgww 	{
44500Sstevel@tonic-gate 		struct bandinfo binfo;
44510Sstevel@tonic-gate 
44520Sstevel@tonic-gate 		error = strcopyin((void *)arg, &binfo, sizeof (binfo),
44530Sstevel@tonic-gate 		    copyflag);
44540Sstevel@tonic-gate 		if (error)
44550Sstevel@tonic-gate 			return (error);
44560Sstevel@tonic-gate 		if (stp->sd_flag & STRHUP)
44570Sstevel@tonic-gate 			return (ENXIO);
44580Sstevel@tonic-gate 		if (binfo.bi_flag & ~FLUSHRW)
44590Sstevel@tonic-gate 			return (EINVAL);
44600Sstevel@tonic-gate 		while (!(mp = allocb(2, BPRI_HI))) {
44610Sstevel@tonic-gate 			if (error = strwaitbuf(2, BPRI_HI))
44620Sstevel@tonic-gate 				return (error);
44630Sstevel@tonic-gate 		}
44640Sstevel@tonic-gate 		mp->b_datap->db_type = M_FLUSH;
44650Sstevel@tonic-gate 		*mp->b_wptr++ = binfo.bi_flag | FLUSHBAND;
44660Sstevel@tonic-gate 		*mp->b_wptr++ = binfo.bi_pri;
44670Sstevel@tonic-gate 		putnext(stp->sd_wrq, mp);
44680Sstevel@tonic-gate 		/*
44690Sstevel@tonic-gate 		 * Send down an unsupported ioctl and wait for the nack
44700Sstevel@tonic-gate 		 * in order to allow the M_FLUSH to propagate back
44710Sstevel@tonic-gate 		 * up to the stream head.
44720Sstevel@tonic-gate 		 * Replaces if (qready()) runqueues();
44730Sstevel@tonic-gate 		 */
44740Sstevel@tonic-gate 		strioc.ic_cmd = -1;	/* The unsupported ioctl */
44750Sstevel@tonic-gate 		strioc.ic_timout = 0;
44760Sstevel@tonic-gate 		strioc.ic_len = 0;
44770Sstevel@tonic-gate 		strioc.ic_dp = NULL;
44780Sstevel@tonic-gate 		(void) strdoioctl(stp, &strioc, flag, K_TO_K, crp, rvalp);
44790Sstevel@tonic-gate 		*rvalp = 0;
44800Sstevel@tonic-gate 		return (0);
44815753Sgww 	}
44820Sstevel@tonic-gate 
44830Sstevel@tonic-gate 	case I_SRDOPT:
44840Sstevel@tonic-gate 		/*
44850Sstevel@tonic-gate 		 * Set read options
44860Sstevel@tonic-gate 		 *
44870Sstevel@tonic-gate 		 * RNORM - default stream mode
44880Sstevel@tonic-gate 		 * RMSGN - message no discard
44890Sstevel@tonic-gate 		 * RMSGD - message discard
44900Sstevel@tonic-gate 		 * RPROTNORM - fail read with EBADMSG for M_[PC]PROTOs
44910Sstevel@tonic-gate 		 * RPROTDAT - convert M_[PC]PROTOs to M_DATAs
44920Sstevel@tonic-gate 		 * RPROTDIS - discard M_[PC]PROTOs and retain M_DATAs
44930Sstevel@tonic-gate 		 */
44940Sstevel@tonic-gate 		if (arg & ~(RMODEMASK | RPROTMASK))
44950Sstevel@tonic-gate 			return (EINVAL);
44960Sstevel@tonic-gate 
44970Sstevel@tonic-gate 		if ((arg & (RMSGD|RMSGN)) == (RMSGD|RMSGN))
44980Sstevel@tonic-gate 			return (EINVAL);
44990Sstevel@tonic-gate 
45000Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
45010Sstevel@tonic-gate 		switch (arg & RMODEMASK) {
45020Sstevel@tonic-gate 		case RNORM:
45030Sstevel@tonic-gate 			stp->sd_read_opt &= ~(RD_MSGDIS | RD_MSGNODIS);
45040Sstevel@tonic-gate 			break;
45050Sstevel@tonic-gate 		case RMSGD:
45060Sstevel@tonic-gate 			stp->sd_read_opt = (stp->sd_read_opt & ~RD_MSGNODIS) |
45070Sstevel@tonic-gate 			    RD_MSGDIS;
45080Sstevel@tonic-gate 			break;
45090Sstevel@tonic-gate 		case RMSGN:
45100Sstevel@tonic-gate 			stp->sd_read_opt = (stp->sd_read_opt & ~RD_MSGDIS) |
45110Sstevel@tonic-gate 			    RD_MSGNODIS;
45120Sstevel@tonic-gate 			break;
45130Sstevel@tonic-gate 		}
45140Sstevel@tonic-gate 
45150Sstevel@tonic-gate 		switch (arg & RPROTMASK) {
45160Sstevel@tonic-gate 		case RPROTNORM:
45170Sstevel@tonic-gate 			stp->sd_read_opt &= ~(RD_PROTDAT | RD_PROTDIS);
45180Sstevel@tonic-gate 			break;
45190Sstevel@tonic-gate 
45200Sstevel@tonic-gate 		case RPROTDAT:
45210Sstevel@tonic-gate 			stp->sd_read_opt = ((stp->sd_read_opt & ~RD_PROTDIS) |
45220Sstevel@tonic-gate 			    RD_PROTDAT);
45230Sstevel@tonic-gate 			break;
45240Sstevel@tonic-gate 
45250Sstevel@tonic-gate 		case RPROTDIS:
45260Sstevel@tonic-gate 			stp->sd_read_opt = ((stp->sd_read_opt & ~RD_PROTDAT) |
45270Sstevel@tonic-gate 			    RD_PROTDIS);
45280Sstevel@tonic-gate 			break;
45290Sstevel@tonic-gate 		}
45300Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
45310Sstevel@tonic-gate 		return (0);
45320Sstevel@tonic-gate 
45330Sstevel@tonic-gate 	case I_GRDOPT:
45340Sstevel@tonic-gate 		/*
45350Sstevel@tonic-gate 		 * Get read option and return the value
45360Sstevel@tonic-gate 		 * to spot pointed to by arg
45370Sstevel@tonic-gate 		 */
45385753Sgww 	{
45390Sstevel@tonic-gate 		int rdopt;
45400Sstevel@tonic-gate 
45410Sstevel@tonic-gate 		rdopt = ((stp->sd_read_opt & RD_MSGDIS) ? RMSGD :
45420Sstevel@tonic-gate 		    ((stp->sd_read_opt & RD_MSGNODIS) ? RMSGN : RNORM));
45430Sstevel@tonic-gate 		rdopt |= ((stp->sd_read_opt & RD_PROTDAT) ? RPROTDAT :
45440Sstevel@tonic-gate 		    ((stp->sd_read_opt & RD_PROTDIS) ? RPROTDIS : RPROTNORM));
45450Sstevel@tonic-gate 
45460Sstevel@tonic-gate 		return (strcopyout(&rdopt, (void *)arg, sizeof (int),
45470Sstevel@tonic-gate 		    copyflag));
45485753Sgww 	}
45490Sstevel@tonic-gate 
45500Sstevel@tonic-gate 	case I_SERROPT:
45510Sstevel@tonic-gate 		/*
45520Sstevel@tonic-gate 		 * Set error options
45530Sstevel@tonic-gate 		 *
45540Sstevel@tonic-gate 		 * RERRNORM - persistent read errors
45550Sstevel@tonic-gate 		 * RERRNONPERSIST - non-persistent read errors
45560Sstevel@tonic-gate 		 * WERRNORM - persistent write errors
45570Sstevel@tonic-gate 		 * WERRNONPERSIST - non-persistent write errors
45580Sstevel@tonic-gate 		 */
45590Sstevel@tonic-gate 		if (arg & ~(RERRMASK | WERRMASK))
45600Sstevel@tonic-gate 			return (EINVAL);
45610Sstevel@tonic-gate 
45620Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
45630Sstevel@tonic-gate 		switch (arg & RERRMASK) {
45640Sstevel@tonic-gate 		case RERRNORM:
45650Sstevel@tonic-gate 			stp->sd_flag &= ~STRDERRNONPERSIST;
45660Sstevel@tonic-gate 			break;
45670Sstevel@tonic-gate 		case RERRNONPERSIST:
45680Sstevel@tonic-gate 			stp->sd_flag |= STRDERRNONPERSIST;
45690Sstevel@tonic-gate 			break;
45700Sstevel@tonic-gate 		}
45710Sstevel@tonic-gate 		switch (arg & WERRMASK) {
45720Sstevel@tonic-gate 		case WERRNORM:
45730Sstevel@tonic-gate 			stp->sd_flag &= ~STWRERRNONPERSIST;
45740Sstevel@tonic-gate 			break;
45750Sstevel@tonic-gate 		case WERRNONPERSIST:
45760Sstevel@tonic-gate 			stp->sd_flag |= STWRERRNONPERSIST;
45770Sstevel@tonic-gate 			break;
45780Sstevel@tonic-gate 		}
45790Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
45800Sstevel@tonic-gate 		return (0);
45810Sstevel@tonic-gate 
45820Sstevel@tonic-gate 	case I_GERROPT:
45830Sstevel@tonic-gate 		/*
45840Sstevel@tonic-gate 		 * Get error option and return the value
45850Sstevel@tonic-gate 		 * to spot pointed to by arg
45860Sstevel@tonic-gate 		 */
45875753Sgww 	{
45880Sstevel@tonic-gate 		int erropt = 0;
45890Sstevel@tonic-gate 
45900Sstevel@tonic-gate 		erropt |= (stp->sd_flag & STRDERRNONPERSIST) ? RERRNONPERSIST :
45915753Sgww 		    RERRNORM;
45920Sstevel@tonic-gate 		erropt |= (stp->sd_flag & STWRERRNONPERSIST) ? WERRNONPERSIST :
45935753Sgww 		    WERRNORM;
45940Sstevel@tonic-gate 		return (strcopyout(&erropt, (void *)arg, sizeof (int),
45950Sstevel@tonic-gate 		    copyflag));
45965753Sgww 	}
45970Sstevel@tonic-gate 
45980Sstevel@tonic-gate 	case I_SETSIG:
45990Sstevel@tonic-gate 		/*
46000Sstevel@tonic-gate 		 * Register the calling proc to receive the SIGPOLL
46010Sstevel@tonic-gate 		 * signal based on the events given in arg.  If
46020Sstevel@tonic-gate 		 * arg is zero, remove the proc from register list.
46030Sstevel@tonic-gate 		 */
46045753Sgww 	{
46050Sstevel@tonic-gate 		strsig_t *ssp, *pssp;
46060Sstevel@tonic-gate 		struct pid *pidp;
46070Sstevel@tonic-gate 
46080Sstevel@tonic-gate 		pssp = NULL;
46090Sstevel@tonic-gate 		pidp = curproc->p_pidp;
46100Sstevel@tonic-gate 		/*
46110Sstevel@tonic-gate 		 * Hold sd_lock to prevent traversal of sd_siglist while
46120Sstevel@tonic-gate 		 * it is modified.
46130Sstevel@tonic-gate 		 */
46140Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
46150Sstevel@tonic-gate 		for (ssp = stp->sd_siglist; ssp && (ssp->ss_pidp != pidp);
46165753Sgww 		    pssp = ssp, ssp = ssp->ss_next)
46170Sstevel@tonic-gate 			;
46180Sstevel@tonic-gate 
46190Sstevel@tonic-gate 		if (arg) {
46200Sstevel@tonic-gate 			if (arg & ~(S_INPUT|S_HIPRI|S_MSG|S_HANGUP|S_ERROR|
46210Sstevel@tonic-gate 			    S_RDNORM|S_WRNORM|S_RDBAND|S_WRBAND|S_BANDURG)) {
46220Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
46230Sstevel@tonic-gate 				return (EINVAL);
46240Sstevel@tonic-gate 			}
46250Sstevel@tonic-gate 			if ((arg & S_BANDURG) && !(arg & S_RDBAND)) {
46260Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
46270Sstevel@tonic-gate 				return (EINVAL);
46280Sstevel@tonic-gate 			}
46290Sstevel@tonic-gate 
46300Sstevel@tonic-gate 			/*
46310Sstevel@tonic-gate 			 * If proc not already registered, add it
46320Sstevel@tonic-gate 			 * to list.
46330Sstevel@tonic-gate 			 */
46340Sstevel@tonic-gate 			if (!ssp) {
46350Sstevel@tonic-gate 				ssp = kmem_alloc(sizeof (strsig_t), KM_SLEEP);
46360Sstevel@tonic-gate 				ssp->ss_pidp = pidp;
46370Sstevel@tonic-gate 				ssp->ss_pid = pidp->pid_id;
46380Sstevel@tonic-gate 				ssp->ss_next = NULL;
46390Sstevel@tonic-gate 				if (pssp)
46400Sstevel@tonic-gate 					pssp->ss_next = ssp;
46410Sstevel@tonic-gate 				else
46420Sstevel@tonic-gate 					stp->sd_siglist = ssp;
46430Sstevel@tonic-gate 				mutex_enter(&pidlock);
46440Sstevel@tonic-gate 				PID_HOLD(pidp);
46450Sstevel@tonic-gate 				mutex_exit(&pidlock);
46460Sstevel@tonic-gate 			}
46470Sstevel@tonic-gate 
46480Sstevel@tonic-gate 			/*
46490Sstevel@tonic-gate 			 * Set events.
46500Sstevel@tonic-gate 			 */
46510Sstevel@tonic-gate 			ssp->ss_events = (int)arg;
46520Sstevel@tonic-gate 		} else {
46530Sstevel@tonic-gate 			/*
46540Sstevel@tonic-gate 			 * Remove proc from register list.
46550Sstevel@tonic-gate 			 */
46560Sstevel@tonic-gate 			if (ssp) {
46570Sstevel@tonic-gate 				mutex_enter(&pidlock);
46580Sstevel@tonic-gate 				PID_RELE(pidp);
46590Sstevel@tonic-gate 				mutex_exit(&pidlock);
46600Sstevel@tonic-gate 				if (pssp)
46610Sstevel@tonic-gate 					pssp->ss_next = ssp->ss_next;
46620Sstevel@tonic-gate 				else
46630Sstevel@tonic-gate 					stp->sd_siglist = ssp->ss_next;
46640Sstevel@tonic-gate 				kmem_free(ssp, sizeof (strsig_t));
46650Sstevel@tonic-gate 			} else {
46660Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
46670Sstevel@tonic-gate 				return (EINVAL);
46680Sstevel@tonic-gate 			}
46690Sstevel@tonic-gate 		}
46700Sstevel@tonic-gate 
46710Sstevel@tonic-gate 		/*
46720Sstevel@tonic-gate 		 * Recalculate OR of sig events.
46730Sstevel@tonic-gate 		 */
46740Sstevel@tonic-gate 		stp->sd_sigflags = 0;
46750Sstevel@tonic-gate 		for (ssp = stp->sd_siglist; ssp; ssp = ssp->ss_next)
46760Sstevel@tonic-gate 			stp->sd_sigflags |= ssp->ss_events;
46770Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
46780Sstevel@tonic-gate 		return (0);
46795753Sgww 	}
46800Sstevel@tonic-gate 
46810Sstevel@tonic-gate 	case I_GETSIG:
46820Sstevel@tonic-gate 		/*
46830Sstevel@tonic-gate 		 * Return (in arg) the current registration of events
46840Sstevel@tonic-gate 		 * for which the calling proc is to be signaled.
46850Sstevel@tonic-gate 		 */
46865753Sgww 	{
46870Sstevel@tonic-gate 		struct strsig *ssp;
46880Sstevel@tonic-gate 		struct pid  *pidp;
46890Sstevel@tonic-gate 
46900Sstevel@tonic-gate 		pidp = curproc->p_pidp;
46910Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
46920Sstevel@tonic-gate 		for (ssp = stp->sd_siglist; ssp; ssp = ssp->ss_next)
46930Sstevel@tonic-gate 			if (ssp->ss_pidp == pidp) {
46940Sstevel@tonic-gate 				error = strcopyout(&ssp->ss_events, (void *)arg,
46950Sstevel@tonic-gate 				    sizeof (int), copyflag);
46960Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
46970Sstevel@tonic-gate 				return (error);
46980Sstevel@tonic-gate 			}
46990Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
47000Sstevel@tonic-gate 		return (EINVAL);
47015753Sgww 	}
47020Sstevel@tonic-gate 
47030Sstevel@tonic-gate 	case I_ESETSIG:
47040Sstevel@tonic-gate 		/*
47050Sstevel@tonic-gate 		 * Register the ss_pid to receive the SIGPOLL
47060Sstevel@tonic-gate 		 * signal based on the events is ss_events arg.  If
47070Sstevel@tonic-gate 		 * ss_events is zero, remove the proc from register list.
47080Sstevel@tonic-gate 		 */
47090Sstevel@tonic-gate 	{
47100Sstevel@tonic-gate 		struct strsig *ssp, *pssp;
47110Sstevel@tonic-gate 		struct proc *proc;
47120Sstevel@tonic-gate 		struct pid  *pidp;
47130Sstevel@tonic-gate 		pid_t pid;
47140Sstevel@tonic-gate 		struct strsigset ss;
47150Sstevel@tonic-gate 
47160Sstevel@tonic-gate 		error = strcopyin((void *)arg, &ss, sizeof (ss), copyflag);
47170Sstevel@tonic-gate 		if (error)
47180Sstevel@tonic-gate 			return (error);
47190Sstevel@tonic-gate 
47200Sstevel@tonic-gate 		pid = ss.ss_pid;
47210Sstevel@tonic-gate 
47220Sstevel@tonic-gate 		if (ss.ss_events != 0) {
47230Sstevel@tonic-gate 			/*
47240Sstevel@tonic-gate 			 * Permissions check by sending signal 0.
47250Sstevel@tonic-gate 			 * Note that when kill fails it does a set_errno
47260Sstevel@tonic-gate 			 * causing the system call to fail.
47270Sstevel@tonic-gate 			 */
47280Sstevel@tonic-gate 			error = kill(pid, 0);
47290Sstevel@tonic-gate 			if (error) {
47300Sstevel@tonic-gate 				return (error);
47310Sstevel@tonic-gate 			}
47320Sstevel@tonic-gate 		}
47330Sstevel@tonic-gate 		mutex_enter(&pidlock);
47340Sstevel@tonic-gate 		if (pid == 0)
47350Sstevel@tonic-gate 			proc = curproc;
47360Sstevel@tonic-gate 		else if (pid < 0)
47370Sstevel@tonic-gate 			proc = pgfind(-pid);
47380Sstevel@tonic-gate 		else
47390Sstevel@tonic-gate 			proc = prfind(pid);
47400Sstevel@tonic-gate 		if (proc == NULL) {
47410Sstevel@tonic-gate 			mutex_exit(&pidlock);
47420Sstevel@tonic-gate 			return (ESRCH);
47430Sstevel@tonic-gate 		}
47440Sstevel@tonic-gate 		if (pid < 0)
47450Sstevel@tonic-gate 			pidp = proc->p_pgidp;
47460Sstevel@tonic-gate 		else
47470Sstevel@tonic-gate 			pidp = proc->p_pidp;
47480Sstevel@tonic-gate 		ASSERT(pidp);
47490Sstevel@tonic-gate 		/*
47500Sstevel@tonic-gate 		 * Get a hold on the pid structure while referencing it.
47510Sstevel@tonic-gate 		 * There is a separate PID_HOLD should it be inserted
47520Sstevel@tonic-gate 		 * in the list below.
47530Sstevel@tonic-gate 		 */
47540Sstevel@tonic-gate 		PID_HOLD(pidp);
47550Sstevel@tonic-gate 		mutex_exit(&pidlock);
47560Sstevel@tonic-gate 
47570Sstevel@tonic-gate 		pssp = NULL;
47580Sstevel@tonic-gate 		/*
47590Sstevel@tonic-gate 		 * Hold sd_lock to prevent traversal of sd_siglist while
47600Sstevel@tonic-gate 		 * it is modified.
47610Sstevel@tonic-gate 		 */
47620Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
47630Sstevel@tonic-gate 		for (ssp = stp->sd_siglist; ssp && (ssp->ss_pid != pid);
47645753Sgww 		    pssp = ssp, ssp = ssp->ss_next)
47650Sstevel@tonic-gate 			;
47660Sstevel@tonic-gate 
47670Sstevel@tonic-gate 		if (ss.ss_events) {
47680Sstevel@tonic-gate 			if (ss.ss_events &
47690Sstevel@tonic-gate 			    ~(S_INPUT|S_HIPRI|S_MSG|S_HANGUP|S_ERROR|
47700Sstevel@tonic-gate 			    S_RDNORM|S_WRNORM|S_RDBAND|S_WRBAND|S_BANDURG)) {
47710Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
47720Sstevel@tonic-gate 				mutex_enter(&pidlock);
47730Sstevel@tonic-gate 				PID_RELE(pidp);
47740Sstevel@tonic-gate 				mutex_exit(&pidlock);
47750Sstevel@tonic-gate 				return (EINVAL);
47760Sstevel@tonic-gate 			}
47770Sstevel@tonic-gate 			if ((ss.ss_events & S_BANDURG) &&
47780Sstevel@tonic-gate 			    !(ss.ss_events & S_RDBAND)) {
47790Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
47800Sstevel@tonic-gate 				mutex_enter(&pidlock);
47810Sstevel@tonic-gate 				PID_RELE(pidp);
47820Sstevel@tonic-gate 				mutex_exit(&pidlock);
47830Sstevel@tonic-gate 				return (EINVAL);
47840Sstevel@tonic-gate 			}
47850Sstevel@tonic-gate 
47860Sstevel@tonic-gate 			/*
47870Sstevel@tonic-gate 			 * If proc not already registered, add it
47880Sstevel@tonic-gate 			 * to list.
47890Sstevel@tonic-gate 			 */
47900Sstevel@tonic-gate 			if (!ssp) {
47910Sstevel@tonic-gate 				ssp = kmem_alloc(sizeof (strsig_t), KM_SLEEP);
47920Sstevel@tonic-gate 				ssp->ss_pidp = pidp;
47930Sstevel@tonic-gate 				ssp->ss_pid = pid;
47940Sstevel@tonic-gate 				ssp->ss_next = NULL;
47950Sstevel@tonic-gate 				if (pssp)
47960Sstevel@tonic-gate 					pssp->ss_next = ssp;
47970Sstevel@tonic-gate 				else
47980Sstevel@tonic-gate 					stp->sd_siglist = ssp;
47990Sstevel@tonic-gate 				mutex_enter(&pidlock);
48000Sstevel@tonic-gate 				PID_HOLD(pidp);
48010Sstevel@tonic-gate 				mutex_exit(&pidlock);
48020Sstevel@tonic-gate 			}
48030Sstevel@tonic-gate 
48040Sstevel@tonic-gate 			/*
48050Sstevel@tonic-gate 			 * Set events.
48060Sstevel@tonic-gate 			 */
48070Sstevel@tonic-gate 			ssp->ss_events = ss.ss_events;
48080Sstevel@tonic-gate 		} else {
48090Sstevel@tonic-gate 			/*
48100Sstevel@tonic-gate 			 * Remove proc from register list.
48110Sstevel@tonic-gate 			 */
48120Sstevel@tonic-gate 			if (ssp) {
48130Sstevel@tonic-gate 				mutex_enter(&pidlock);
48140Sstevel@tonic-gate 				PID_RELE(pidp);
48150Sstevel@tonic-gate 				mutex_exit(&pidlock);
48160Sstevel@tonic-gate 				if (pssp)
48170Sstevel@tonic-gate 					pssp->ss_next = ssp->ss_next;
48180Sstevel@tonic-gate 				else
48190Sstevel@tonic-gate 					stp->sd_siglist = ssp->ss_next;
48200Sstevel@tonic-gate 				kmem_free(ssp, sizeof (strsig_t));
48210Sstevel@tonic-gate 			} else {
48220Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
48230Sstevel@tonic-gate 				mutex_enter(&pidlock);
48240Sstevel@tonic-gate 				PID_RELE(pidp);
48250Sstevel@tonic-gate 				mutex_exit(&pidlock);
48260Sstevel@tonic-gate 				return (EINVAL);
48270Sstevel@tonic-gate 			}
48280Sstevel@tonic-gate 		}
48290Sstevel@tonic-gate 
48300Sstevel@tonic-gate 		/*
48310Sstevel@tonic-gate 		 * Recalculate OR of sig events.
48320Sstevel@tonic-gate 		 */
48330Sstevel@tonic-gate 		stp->sd_sigflags = 0;
48340Sstevel@tonic-gate 		for (ssp = stp->sd_siglist; ssp; ssp = ssp->ss_next)
48350Sstevel@tonic-gate 			stp->sd_sigflags |= ssp->ss_events;
48360Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
48370Sstevel@tonic-gate 		mutex_enter(&pidlock);
48380Sstevel@tonic-gate 		PID_RELE(pidp);
48390Sstevel@tonic-gate 		mutex_exit(&pidlock);
48400Sstevel@tonic-gate 		return (0);
48415753Sgww 	}
48420Sstevel@tonic-gate 
48430Sstevel@tonic-gate 	case I_EGETSIG:
48440Sstevel@tonic-gate 		/*
48450Sstevel@tonic-gate 		 * Return (in arg) the current registration of events
48460Sstevel@tonic-gate 		 * for which the calling proc is to be signaled.
48470Sstevel@tonic-gate 		 */
48485753Sgww 	{
48490Sstevel@tonic-gate 		struct strsig *ssp;
48500Sstevel@tonic-gate 		struct proc *proc;
48510Sstevel@tonic-gate 		pid_t pid;
48520Sstevel@tonic-gate 		struct pid  *pidp;
48530Sstevel@tonic-gate 		struct strsigset ss;
48540Sstevel@tonic-gate 
48550Sstevel@tonic-gate 		error = strcopyin((void *)arg, &ss, sizeof (ss), copyflag);
48560Sstevel@tonic-gate 		if (error)
48570Sstevel@tonic-gate 			return (error);
48580Sstevel@tonic-gate 
48590Sstevel@tonic-gate 		pid = ss.ss_pid;
48600Sstevel@tonic-gate 		mutex_enter(&pidlock);
48610Sstevel@tonic-gate 		if (pid == 0)
48620Sstevel@tonic-gate 			proc = curproc;
48630Sstevel@tonic-gate 		else if (pid < 0)
48640Sstevel@tonic-gate 			proc = pgfind(-pid);
48650Sstevel@tonic-gate 		else
48660Sstevel@tonic-gate 			proc = prfind(pid);
48670Sstevel@tonic-gate 		if (proc == NULL) {
48680Sstevel@tonic-gate 			mutex_exit(&pidlock);
48690Sstevel@tonic-gate 			return (ESRCH);
48700Sstevel@tonic-gate 		}
48710Sstevel@tonic-gate 		if (pid < 0)
48720Sstevel@tonic-gate 			pidp = proc->p_pgidp;
48730Sstevel@tonic-gate 		else
48740Sstevel@tonic-gate 			pidp = proc->p_pidp;
48750Sstevel@tonic-gate 
48760Sstevel@tonic-gate 		/* Prevent the pidp from being reassigned */
48770Sstevel@tonic-gate 		PID_HOLD(pidp);
48780Sstevel@tonic-gate 		mutex_exit(&pidlock);
48790Sstevel@tonic-gate 
48800Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
48810Sstevel@tonic-gate 		for (ssp = stp->sd_siglist; ssp; ssp = ssp->ss_next)
48820Sstevel@tonic-gate 			if (ssp->ss_pid == pid) {
48830Sstevel@tonic-gate 				ss.ss_pid = ssp->ss_pid;
48840Sstevel@tonic-gate 				ss.ss_events = ssp->ss_events;
48850Sstevel@tonic-gate 				error = strcopyout(&ss, (void *)arg,
48860Sstevel@tonic-gate 				    sizeof (struct strsigset), copyflag);
48870Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
48880Sstevel@tonic-gate 				mutex_enter(&pidlock);
48890Sstevel@tonic-gate 				PID_RELE(pidp);
48900Sstevel@tonic-gate 				mutex_exit(&pidlock);
48910Sstevel@tonic-gate 				return (error);
48920Sstevel@tonic-gate 			}
48930Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
48940Sstevel@tonic-gate 		mutex_enter(&pidlock);
48950Sstevel@tonic-gate 		PID_RELE(pidp);
48960Sstevel@tonic-gate 		mutex_exit(&pidlock);
48970Sstevel@tonic-gate 		return (EINVAL);
48985753Sgww 	}
48990Sstevel@tonic-gate 
49000Sstevel@tonic-gate 	case I_PEEK:
49015753Sgww 	{
49020Sstevel@tonic-gate 		STRUCT_DECL(strpeek, strpeek);
49030Sstevel@tonic-gate 		size_t n;
49040Sstevel@tonic-gate 		mblk_t *fmp, *tmp_mp = NULL;
49050Sstevel@tonic-gate 
49060Sstevel@tonic-gate 		STRUCT_INIT(strpeek, flag);
49070Sstevel@tonic-gate 
49080Sstevel@tonic-gate 		error = strcopyin((void *)arg, STRUCT_BUF(strpeek),
49090Sstevel@tonic-gate 		    STRUCT_SIZE(strpeek), copyflag);
49100Sstevel@tonic-gate 		if (error)
49110Sstevel@tonic-gate 			return (error);
49120Sstevel@tonic-gate 
49130Sstevel@tonic-gate 		mutex_enter(QLOCK(rdq));
49140Sstevel@tonic-gate 		/*
49150Sstevel@tonic-gate 		 * Skip the invalid messages
49160Sstevel@tonic-gate 		 */
49170Sstevel@tonic-gate 		for (mp = rdq->q_first; mp != NULL; mp = mp->b_next)
49180Sstevel@tonic-gate 			if (mp->b_datap->db_type != M_SIG)
49190Sstevel@tonic-gate 				break;
49200Sstevel@tonic-gate 
49210Sstevel@tonic-gate 		/*
49220Sstevel@tonic-gate 		 * If user has requested to peek at a high priority message
49230Sstevel@tonic-gate 		 * and first message is not, return 0
49240Sstevel@tonic-gate 		 */
49250Sstevel@tonic-gate 		if (mp != NULL) {
49260Sstevel@tonic-gate 			if ((STRUCT_FGET(strpeek, flags) & RS_HIPRI) &&
49270Sstevel@tonic-gate 			    queclass(mp) == QNORM) {
49280Sstevel@tonic-gate 				*rvalp = 0;
49290Sstevel@tonic-gate 				mutex_exit(QLOCK(rdq));
49300Sstevel@tonic-gate 				return (0);
49310Sstevel@tonic-gate 			}
49320Sstevel@tonic-gate 		} else if (stp->sd_struiordq == NULL ||
49330Sstevel@tonic-gate 		    (STRUCT_FGET(strpeek, flags) & RS_HIPRI)) {
49340Sstevel@tonic-gate 			/*
49350Sstevel@tonic-gate 			 * No mblks to look at at the streamhead and
49360Sstevel@tonic-gate 			 * 1). This isn't a synch stream or
49370Sstevel@tonic-gate 			 * 2). This is a synch stream but caller wants high
49380Sstevel@tonic-gate 			 *	priority messages which is not supported by
49390Sstevel@tonic-gate 			 *	the synch stream. (it only supports QNORM)
49400Sstevel@tonic-gate 			 */
49410Sstevel@tonic-gate 			*rvalp = 0;
49420Sstevel@tonic-gate 			mutex_exit(QLOCK(rdq));
49430Sstevel@tonic-gate 			return (0);
49440Sstevel@tonic-gate 		}
49450Sstevel@tonic-gate 
49460Sstevel@tonic-gate 		fmp = mp;
49470Sstevel@tonic-gate 
49480Sstevel@tonic-gate 		if (mp && mp->b_datap->db_type == M_PASSFP) {
49490Sstevel@tonic-gate 			mutex_exit(QLOCK(rdq));
49500Sstevel@tonic-gate 			return (EBADMSG);
49510Sstevel@tonic-gate 		}
49520Sstevel@tonic-gate 
49530Sstevel@tonic-gate 		ASSERT(mp == NULL || mp->b_datap->db_type == M_PCPROTO ||
49540Sstevel@tonic-gate 		    mp->b_datap->db_type == M_PROTO ||
49550Sstevel@tonic-gate 		    mp->b_datap->db_type == M_DATA);
49560Sstevel@tonic-gate 
49570Sstevel@tonic-gate 		if (mp && mp->b_datap->db_type == M_PCPROTO) {
49580Sstevel@tonic-gate 			STRUCT_FSET(strpeek, flags, RS_HIPRI);
49590Sstevel@tonic-gate 		} else {
49600Sstevel@tonic-gate 			STRUCT_FSET(strpeek, flags, 0);
49610Sstevel@tonic-gate 		}
49620Sstevel@tonic-gate 
49630Sstevel@tonic-gate 
49640Sstevel@tonic-gate 		if (mp && ((tmp_mp = dupmsg(mp)) == NULL)) {
49650Sstevel@tonic-gate 			mutex_exit(QLOCK(rdq));
49660Sstevel@tonic-gate 			return (ENOSR);
49670Sstevel@tonic-gate 		}
49680Sstevel@tonic-gate 		mutex_exit(QLOCK(rdq));
49690Sstevel@tonic-gate 
49700Sstevel@tonic-gate 		/*
49710Sstevel@tonic-gate 		 * set mp = tmp_mp, so that I_PEEK processing can continue.
49720Sstevel@tonic-gate 		 * tmp_mp is used to free the dup'd message.
49730Sstevel@tonic-gate 		 */
49740Sstevel@tonic-gate 		mp = tmp_mp;
49750Sstevel@tonic-gate 
49760Sstevel@tonic-gate 		uio.uio_fmode = 0;
49770Sstevel@tonic-gate 		uio.uio_extflg = UIO_COPY_CACHED;
49780Sstevel@tonic-gate 		uio.uio_segflg = (copyflag == U_TO_K) ? UIO_USERSPACE :
49790Sstevel@tonic-gate 		    UIO_SYSSPACE;
49800Sstevel@tonic-gate 		uio.uio_limit = 0;
49810Sstevel@tonic-gate 		/*
49820Sstevel@tonic-gate 		 * First process PROTO blocks, if any.
49830Sstevel@tonic-gate 		 * If user doesn't want to get ctl info by setting maxlen <= 0,
49840Sstevel@tonic-gate 		 * then set len to -1/0 and skip control blocks part.
49850Sstevel@tonic-gate 		 */
49860Sstevel@tonic-gate 		if (STRUCT_FGET(strpeek, ctlbuf.maxlen) < 0)
49870Sstevel@tonic-gate 			STRUCT_FSET(strpeek, ctlbuf.len, -1);
49880Sstevel@tonic-gate 		else if (STRUCT_FGET(strpeek, ctlbuf.maxlen) == 0)
49890Sstevel@tonic-gate 			STRUCT_FSET(strpeek, ctlbuf.len, 0);
49900Sstevel@tonic-gate 		else {
49910Sstevel@tonic-gate 			int	ctl_part = 0;
49920Sstevel@tonic-gate 
49930Sstevel@tonic-gate 			iov.iov_base = STRUCT_FGETP(strpeek, ctlbuf.buf);
49940Sstevel@tonic-gate 			iov.iov_len = STRUCT_FGET(strpeek, ctlbuf.maxlen);
49950Sstevel@tonic-gate 			uio.uio_iov = &iov;
49960Sstevel@tonic-gate 			uio.uio_resid = iov.iov_len;
49970Sstevel@tonic-gate 			uio.uio_loffset = 0;
49980Sstevel@tonic-gate 			uio.uio_iovcnt = 1;
49990Sstevel@tonic-gate 			while (mp && mp->b_datap->db_type != M_DATA &&
50000Sstevel@tonic-gate 			    uio.uio_resid >= 0) {
50010Sstevel@tonic-gate 				ASSERT(STRUCT_FGET(strpeek, flags) == 0 ?
50020Sstevel@tonic-gate 				    mp->b_datap->db_type == M_PROTO :
50030Sstevel@tonic-gate 				    mp->b_datap->db_type == M_PCPROTO);
50040Sstevel@tonic-gate 
50050Sstevel@tonic-gate 				if ((n = MIN(uio.uio_resid,
50060Sstevel@tonic-gate 				    mp->b_wptr - mp->b_rptr)) != 0 &&
50070Sstevel@tonic-gate 				    (error = uiomove((char *)mp->b_rptr, n,
50080Sstevel@tonic-gate 				    UIO_READ, &uio)) != 0) {
50090Sstevel@tonic-gate 					freemsg(tmp_mp);
50100Sstevel@tonic-gate 					return (error);
50110Sstevel@tonic-gate 				}
50120Sstevel@tonic-gate 				ctl_part = 1;
50130Sstevel@tonic-gate 				mp = mp->b_cont;
50140Sstevel@tonic-gate 			}
50150Sstevel@tonic-gate 			/* No ctl message */
50160Sstevel@tonic-gate 			if (ctl_part == 0)
50170Sstevel@tonic-gate 				STRUCT_FSET(strpeek, ctlbuf.len, -1);
50180Sstevel@tonic-gate 			else
50190Sstevel@tonic-gate 				STRUCT_FSET(strpeek, ctlbuf.len,
50200Sstevel@tonic-gate 				    STRUCT_FGET(strpeek, ctlbuf.maxlen) -
50210Sstevel@tonic-gate 				    uio.uio_resid);
50220Sstevel@tonic-gate 		}
50230Sstevel@tonic-gate 
50240Sstevel@tonic-gate 		/*
50250Sstevel@tonic-gate 		 * Now process DATA blocks, if any.
50260Sstevel@tonic-gate 		 * If user doesn't want to get data info by setting maxlen <= 0,
50270Sstevel@tonic-gate 		 * then set len to -1/0 and skip data blocks part.
50280Sstevel@tonic-gate 		 */
50290Sstevel@tonic-gate 		if (STRUCT_FGET(strpeek, databuf.maxlen) < 0)
50300Sstevel@tonic-gate 			STRUCT_FSET(strpeek, databuf.len, -1);
50310Sstevel@tonic-gate 		else if (STRUCT_FGET(strpeek, databuf.maxlen) == 0)
50320Sstevel@tonic-gate 			STRUCT_FSET(strpeek, databuf.len, 0);
50330Sstevel@tonic-gate 		else {
50340Sstevel@tonic-gate 			int	data_part = 0;
50350Sstevel@tonic-gate 
50360Sstevel@tonic-gate 			iov.iov_base = STRUCT_FGETP(strpeek, databuf.buf);
50370Sstevel@tonic-gate 			iov.iov_len = STRUCT_FGET(strpeek, databuf.maxlen);
50380Sstevel@tonic-gate 			uio.uio_iov = &iov;
50390Sstevel@tonic-gate 			uio.uio_resid = iov.iov_len;
50400Sstevel@tonic-gate 			uio.uio_loffset = 0;
50410Sstevel@tonic-gate 			uio.uio_iovcnt = 1;
50420Sstevel@tonic-gate 			while (mp && uio.uio_resid) {
50430Sstevel@tonic-gate 				if (mp->b_datap->db_type == M_DATA) {
50440Sstevel@tonic-gate 					if ((n = MIN(uio.uio_resid,
50450Sstevel@tonic-gate 					    mp->b_wptr - mp->b_rptr)) != 0 &&
50460Sstevel@tonic-gate 					    (error = uiomove((char *)mp->b_rptr,
50475753Sgww 					    n, UIO_READ, &uio)) != 0) {
50480Sstevel@tonic-gate 						freemsg(tmp_mp);
50490Sstevel@tonic-gate 						return (error);
50500Sstevel@tonic-gate 					}
50510Sstevel@tonic-gate 					data_part = 1;
50520Sstevel@tonic-gate 				}
50530Sstevel@tonic-gate 				ASSERT(data_part == 0 ||
50540Sstevel@tonic-gate 				    mp->b_datap->db_type == M_DATA);
50550Sstevel@tonic-gate 				mp = mp->b_cont;
50560Sstevel@tonic-gate 			}
50570Sstevel@tonic-gate 			/* No data message */
50580Sstevel@tonic-gate 			if (data_part == 0)
50590Sstevel@tonic-gate 				STRUCT_FSET(strpeek, databuf.len, -1);
50600Sstevel@tonic-gate 			else
50610Sstevel@tonic-gate 				STRUCT_FSET(strpeek, databuf.len,
50620Sstevel@tonic-gate 				    STRUCT_FGET(strpeek, databuf.maxlen) -
50630Sstevel@tonic-gate 				    uio.uio_resid);
50640Sstevel@tonic-gate 		}
50650Sstevel@tonic-gate 		freemsg(tmp_mp);
50660Sstevel@tonic-gate 
50670Sstevel@tonic-gate 		/*
50680Sstevel@tonic-gate 		 * It is a synch stream and user wants to get
50690Sstevel@tonic-gate 		 * data (maxlen > 0).
50700Sstevel@tonic-gate 		 * uio setup is done by the codes that process DATA
50710Sstevel@tonic-gate 		 * blocks above.
50720Sstevel@tonic-gate 		 */
50730Sstevel@tonic-gate 		if ((fmp == NULL) && STRUCT_FGET(strpeek, databuf.maxlen) > 0) {
50740Sstevel@tonic-gate 			infod_t infod;
50750Sstevel@tonic-gate 
50760Sstevel@tonic-gate 			infod.d_cmd = INFOD_COPYOUT;
50770Sstevel@tonic-gate 			infod.d_res = 0;
50780Sstevel@tonic-gate 			infod.d_uiop = &uio;
50790Sstevel@tonic-gate 			error = infonext(rdq, &infod);
50800Sstevel@tonic-gate 			if (error == EINVAL || error == EBUSY)
50810Sstevel@tonic-gate 				error = 0;
50820Sstevel@tonic-gate 			if (error)
50830Sstevel@tonic-gate 				return (error);
50840Sstevel@tonic-gate 			STRUCT_FSET(strpeek, databuf.len, STRUCT_FGET(strpeek,
50850Sstevel@tonic-gate 			    databuf.maxlen) - uio.uio_resid);
50860Sstevel@tonic-gate 			if (STRUCT_FGET(strpeek, databuf.len) == 0) {
50870Sstevel@tonic-gate 				/*
50880Sstevel@tonic-gate 				 * No data found by the infonext().
50890Sstevel@tonic-gate 				 */
50900Sstevel@tonic-gate 				STRUCT_FSET(strpeek, databuf.len, -1);
50910Sstevel@tonic-gate 			}
50920Sstevel@tonic-gate 		}
50930Sstevel@tonic-gate 		error = strcopyout(STRUCT_BUF(strpeek), (void *)arg,
50940Sstevel@tonic-gate 		    STRUCT_SIZE(strpeek), copyflag);
50950Sstevel@tonic-gate 		if (error) {
50960Sstevel@tonic-gate 			return (error);
50970Sstevel@tonic-gate 		}
50980Sstevel@tonic-gate 		/*
50990Sstevel@tonic-gate 		 * If there is no message retrieved, set return code to 0
51000Sstevel@tonic-gate 		 * otherwise, set it to 1.
51010Sstevel@tonic-gate 		 */
51020Sstevel@tonic-gate 		if (STRUCT_FGET(strpeek, ctlbuf.len) == -1 &&
51030Sstevel@tonic-gate 		    STRUCT_FGET(strpeek, databuf.len) == -1)
51040Sstevel@tonic-gate 			*rvalp = 0;
51050Sstevel@tonic-gate 		else
51060Sstevel@tonic-gate 			*rvalp = 1;
51070Sstevel@tonic-gate 		return (0);
51085753Sgww 	}
51090Sstevel@tonic-gate 
51100Sstevel@tonic-gate 	case I_FDINSERT:
51115753Sgww 	{
51120Sstevel@tonic-gate 		STRUCT_DECL(strfdinsert, strfdinsert);
51130Sstevel@tonic-gate 		struct file *resftp;
51140Sstevel@tonic-gate 		struct stdata *resstp;
51150Sstevel@tonic-gate 		t_uscalar_t	ival;
51160Sstevel@tonic-gate 		ssize_t msgsize;
51170Sstevel@tonic-gate 		struct strbuf mctl;
51180Sstevel@tonic-gate 
51190Sstevel@tonic-gate 		STRUCT_INIT(strfdinsert, flag);
51200Sstevel@tonic-gate 		if (stp->sd_flag & STRHUP)
51210Sstevel@tonic-gate 			return (ENXIO);
51220Sstevel@tonic-gate 		/*
51230Sstevel@tonic-gate 		 * STRDERR, STWRERR and STPLEX tested above.
51240Sstevel@tonic-gate 		 */
51250Sstevel@tonic-gate 		error = strcopyin((void *)arg, STRUCT_BUF(strfdinsert),
51260Sstevel@tonic-gate 		    STRUCT_SIZE(strfdinsert), copyflag);
51270Sstevel@tonic-gate 		if (error)
51280Sstevel@tonic-gate 			return (error);
51290Sstevel@tonic-gate 
51300Sstevel@tonic-gate 		if (STRUCT_FGET(strfdinsert, offset) < 0 ||
51310Sstevel@tonic-gate 		    (STRUCT_FGET(strfdinsert, offset) %
51320Sstevel@tonic-gate 		    sizeof (t_uscalar_t)) != 0)
51330Sstevel@tonic-gate 			return (EINVAL);
51340Sstevel@tonic-gate 		if ((resftp = getf(STRUCT_FGET(strfdinsert, fildes))) != NULL) {
51350Sstevel@tonic-gate 			if ((resstp = resftp->f_vnode->v_stream) == NULL) {
51360Sstevel@tonic-gate 				releasef(STRUCT_FGET(strfdinsert, fildes));
51370Sstevel@tonic-gate 				return (EINVAL);
51380Sstevel@tonic-gate 			}
51390Sstevel@tonic-gate 		} else
51400Sstevel@tonic-gate 			return (EINVAL);
51410Sstevel@tonic-gate 
51420Sstevel@tonic-gate 		mutex_enter(&resstp->sd_lock);
51430Sstevel@tonic-gate 		if (resstp->sd_flag & (STRDERR|STWRERR|STRHUP|STPLEX)) {
51440Sstevel@tonic-gate 			error = strgeterr(resstp,
51455753Sgww 			    STRDERR|STWRERR|STRHUP|STPLEX, 0);
51460Sstevel@tonic-gate 			if (error != 0) {
51470Sstevel@tonic-gate 				mutex_exit(&resstp->sd_lock);
51480Sstevel@tonic-gate 				releasef(STRUCT_FGET(strfdinsert, fildes));
51490Sstevel@tonic-gate 				return (error);
51500Sstevel@tonic-gate 			}
51510Sstevel@tonic-gate 		}
51520Sstevel@tonic-gate 		mutex_exit(&resstp->sd_lock);
51530Sstevel@tonic-gate 
51540Sstevel@tonic-gate #ifdef	_ILP32
51550Sstevel@tonic-gate 		{
51560Sstevel@tonic-gate 			queue_t	*q;
51570Sstevel@tonic-gate 			queue_t	*mate = NULL;
51580Sstevel@tonic-gate 
51590Sstevel@tonic-gate 			/* get read queue of stream terminus */
51600Sstevel@tonic-gate 			claimstr(resstp->sd_wrq);
51610Sstevel@tonic-gate 			for (q = resstp->sd_wrq->q_next; q->q_next != NULL;
51620Sstevel@tonic-gate 			    q = q->q_next)
51630Sstevel@tonic-gate 				if (!STRMATED(resstp) && STREAM(q) != resstp &&
51640Sstevel@tonic-gate 				    mate == NULL) {
51650Sstevel@tonic-gate 					ASSERT(q->q_qinfo->qi_srvp);
51660Sstevel@tonic-gate 					ASSERT(_OTHERQ(q)->q_qinfo->qi_srvp);
51670Sstevel@tonic-gate 					claimstr(q);
51680Sstevel@tonic-gate 					mate = q;
51690Sstevel@tonic-gate 				}
51700Sstevel@tonic-gate 			q = _RD(q);
51710Sstevel@tonic-gate 			if (mate)
51720Sstevel@tonic-gate 				releasestr(mate);
51730Sstevel@tonic-gate 			releasestr(resstp->sd_wrq);
51740Sstevel@tonic-gate 			ival = (t_uscalar_t)q;
51750Sstevel@tonic-gate 		}
51760Sstevel@tonic-gate #else
51770Sstevel@tonic-gate 		ival = (t_uscalar_t)getminor(resftp->f_vnode->v_rdev);
51780Sstevel@tonic-gate #endif	/* _ILP32 */
51790Sstevel@tonic-gate 
51800Sstevel@tonic-gate 		if (STRUCT_FGET(strfdinsert, ctlbuf.len) <
51810Sstevel@tonic-gate 		    STRUCT_FGET(strfdinsert, offset) + sizeof (t_uscalar_t)) {
51820Sstevel@tonic-gate 			releasef(STRUCT_FGET(strfdinsert, fildes));
51830Sstevel@tonic-gate 			return (EINVAL);
51840Sstevel@tonic-gate 		}
51850Sstevel@tonic-gate 
51860Sstevel@tonic-gate 		/*
51870Sstevel@tonic-gate 		 * Check for legal flag value.
51880Sstevel@tonic-gate 		 */
51890Sstevel@tonic-gate 		if (STRUCT_FGET(strfdinsert, flags) & ~RS_HIPRI) {
51900Sstevel@tonic-gate 			releasef(STRUCT_FGET(strfdinsert, fildes));
51910Sstevel@tonic-gate 			return (EINVAL);
51920Sstevel@tonic-gate 		}
51930Sstevel@tonic-gate 
51940Sstevel@tonic-gate 		/* get these values from those cached in the stream head */
51950Sstevel@tonic-gate 		mutex_enter(QLOCK(stp->sd_wrq));
51960Sstevel@tonic-gate 		rmin = stp->sd_qn_minpsz;
51970Sstevel@tonic-gate 		rmax = stp->sd_qn_maxpsz;
51980Sstevel@tonic-gate 		mutex_exit(QLOCK(stp->sd_wrq));
51990Sstevel@tonic-gate 
52000Sstevel@tonic-gate 		/*
52010Sstevel@tonic-gate 		 * Make sure ctl and data sizes together fall within
52020Sstevel@tonic-gate 		 * the limits of the max and min receive packet sizes
52030Sstevel@tonic-gate 		 * and do not exceed system limit.  A negative data
52040Sstevel@tonic-gate 		 * length means that no data part is to be sent.
52050Sstevel@tonic-gate 		 */
52060Sstevel@tonic-gate 		ASSERT((rmax >= 0) || (rmax == INFPSZ));
52070Sstevel@tonic-gate 		if (rmax == 0) {
52080Sstevel@tonic-gate 			releasef(STRUCT_FGET(strfdinsert, fildes));
52090Sstevel@tonic-gate 			return (ERANGE);
52100Sstevel@tonic-gate 		}
52110Sstevel@tonic-gate 		if ((msgsize = STRUCT_FGET(strfdinsert, databuf.len)) < 0)
52120Sstevel@tonic-gate 			msgsize = 0;
52130Sstevel@tonic-gate 		if ((msgsize < rmin) ||
52140Sstevel@tonic-gate 		    ((msgsize > rmax) && (rmax != INFPSZ)) ||
52150Sstevel@tonic-gate 		    (STRUCT_FGET(strfdinsert, ctlbuf.len) > strctlsz)) {
52160Sstevel@tonic-gate 			releasef(STRUCT_FGET(strfdinsert, fildes));
52170Sstevel@tonic-gate 			return (ERANGE);
52180Sstevel@tonic-gate 		}
52190Sstevel@tonic-gate 
52200Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
52210Sstevel@tonic-gate 		while (!(STRUCT_FGET(strfdinsert, flags) & RS_HIPRI) &&
52220Sstevel@tonic-gate 		    !canputnext(stp->sd_wrq)) {
52230Sstevel@tonic-gate 			if ((error = strwaitq(stp, WRITEWAIT, (ssize_t)0,
52240Sstevel@tonic-gate 			    flag, -1, &done)) != 0 || done) {
52250Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
52260Sstevel@tonic-gate 				releasef(STRUCT_FGET(strfdinsert, fildes));
52270Sstevel@tonic-gate 				return (error);
52280Sstevel@tonic-gate 			}
52292712Snn35248 			if ((error = i_straccess(stp, access)) != 0) {
52300Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
52312712Snn35248 				releasef(
52322712Snn35248 				    STRUCT_FGET(strfdinsert, fildes));
52332712Snn35248 				return (error);
52340Sstevel@tonic-gate 			}
52350Sstevel@tonic-gate 		}
52360Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
52370Sstevel@tonic-gate 
52380Sstevel@tonic-gate 		/*
52390Sstevel@tonic-gate 		 * Copy strfdinsert.ctlbuf into native form of
52400Sstevel@tonic-gate 		 * ctlbuf to pass down into strmakemsg().
52410Sstevel@tonic-gate 		 */
52420Sstevel@tonic-gate 		mctl.maxlen = STRUCT_FGET(strfdinsert, ctlbuf.maxlen);
52430Sstevel@tonic-gate 		mctl.len = STRUCT_FGET(strfdinsert, ctlbuf.len);
52440Sstevel@tonic-gate 		mctl.buf = STRUCT_FGETP(strfdinsert, ctlbuf.buf);
52450Sstevel@tonic-gate 
52460Sstevel@tonic-gate 		iov.iov_base = STRUCT_FGETP(strfdinsert, databuf.buf);
52470Sstevel@tonic-gate 		iov.iov_len = STRUCT_FGET(strfdinsert, databuf.len);
52480Sstevel@tonic-gate 		uio.uio_iov = &iov;
52490Sstevel@tonic-gate 		uio.uio_iovcnt = 1;
52500Sstevel@tonic-gate 		uio.uio_loffset = 0;
52510Sstevel@tonic-gate 		uio.uio_segflg = (copyflag == U_TO_K) ? UIO_USERSPACE :
52520Sstevel@tonic-gate 		    UIO_SYSSPACE;
52530Sstevel@tonic-gate 		uio.uio_fmode = 0;
52540Sstevel@tonic-gate 		uio.uio_extflg = UIO_COPY_CACHED;
52550Sstevel@tonic-gate 		uio.uio_resid = iov.iov_len;
52560Sstevel@tonic-gate 		if ((error = strmakemsg(&mctl,
52570Sstevel@tonic-gate 		    &msgsize, &uio, stp,
52580Sstevel@tonic-gate 		    STRUCT_FGET(strfdinsert, flags), &mp)) != 0 || !mp) {
52590Sstevel@tonic-gate 			STRUCT_FSET(strfdinsert, databuf.len, msgsize);
52600Sstevel@tonic-gate 			releasef(STRUCT_FGET(strfdinsert, fildes));
52610Sstevel@tonic-gate 			return (error);
52620Sstevel@tonic-gate 		}
52630Sstevel@tonic-gate 
52640Sstevel@tonic-gate 		STRUCT_FSET(strfdinsert, databuf.len, msgsize);
52650Sstevel@tonic-gate 
52660Sstevel@tonic-gate 		/*
52670Sstevel@tonic-gate 		 * Place the possibly reencoded queue pointer 'offset' bytes
52680Sstevel@tonic-gate 		 * from the start of the control portion of the message.
52690Sstevel@tonic-gate 		 */
52700Sstevel@tonic-gate 		*((t_uscalar_t *)(mp->b_rptr +
52710Sstevel@tonic-gate 		    STRUCT_FGET(strfdinsert, offset))) = ival;
52720Sstevel@tonic-gate 
52730Sstevel@tonic-gate 		/*
52740Sstevel@tonic-gate 		 * Put message downstream.
52750Sstevel@tonic-gate 		 */
52760Sstevel@tonic-gate 		stream_willservice(stp);
52770Sstevel@tonic-gate 		putnext(stp->sd_wrq, mp);
52780Sstevel@tonic-gate 		stream_runservice(stp);
52790Sstevel@tonic-gate 		releasef(STRUCT_FGET(strfdinsert, fildes));
52800Sstevel@tonic-gate 		return (error);
52815753Sgww 	}
52820Sstevel@tonic-gate 
52830Sstevel@tonic-gate 	case I_SENDFD:
52845753Sgww 	{
52850Sstevel@tonic-gate 		struct file *fp;
52860Sstevel@tonic-gate 
52870Sstevel@tonic-gate 		if ((fp = getf((int)arg)) == NULL)
52880Sstevel@tonic-gate 			return (EBADF);
52890Sstevel@tonic-gate 		error = do_sendfp(stp, fp, crp);
529011861SMarek.Pospisil@Sun.COM 		if (auditing) {
52910Sstevel@tonic-gate 			audit_fdsend((int)arg, fp, error);
52920Sstevel@tonic-gate 		}
52930Sstevel@tonic-gate 		releasef((int)arg);
52940Sstevel@tonic-gate 		return (error);
52955753Sgww 	}
52960Sstevel@tonic-gate 
52970Sstevel@tonic-gate 	case I_RECVFD:
52980Sstevel@tonic-gate 	case I_E_RECVFD:
52995753Sgww 	{
53000Sstevel@tonic-gate 		struct k_strrecvfd *srf;
53010Sstevel@tonic-gate 		int i, fd;
53020Sstevel@tonic-gate 
53030Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
53040Sstevel@tonic-gate 		while (!(mp = getq(rdq))) {
53050Sstevel@tonic-gate 			if (stp->sd_flag & (STRHUP|STREOF)) {
53060Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
53070Sstevel@tonic-gate 				return (ENXIO);
53080Sstevel@tonic-gate 			}
53090Sstevel@tonic-gate 			if ((error = strwaitq(stp, GETWAIT, (ssize_t)0,
53100Sstevel@tonic-gate 			    flag, -1, &done)) != 0 || done) {
53110Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
53120Sstevel@tonic-gate 				return (error);
53130Sstevel@tonic-gate 			}
53142712Snn35248 			if ((error = i_straccess(stp, access)) != 0) {
53150Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
53162712Snn35248 				return (error);
53170Sstevel@tonic-gate 			}
53180Sstevel@tonic-gate 		}
53190Sstevel@tonic-gate 		if (mp->b_datap->db_type != M_PASSFP) {
53200Sstevel@tonic-gate 			putback(stp, rdq, mp, mp->b_band);
53210Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
53220Sstevel@tonic-gate 			return (EBADMSG);
53230Sstevel@tonic-gate 		}
53240Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
53250Sstevel@tonic-gate 
53260Sstevel@tonic-gate 		srf = (struct k_strrecvfd *)mp->b_rptr;
53270Sstevel@tonic-gate 		if ((fd = ufalloc(0)) == -1) {
53280Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
53290Sstevel@tonic-gate 			putback(stp, rdq, mp, mp->b_band);
53300Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
53310Sstevel@tonic-gate 			return (EMFILE);
53320Sstevel@tonic-gate 		}
53330Sstevel@tonic-gate 		if (cmd == I_RECVFD) {
53340Sstevel@tonic-gate 			struct o_strrecvfd	ostrfd;
53350Sstevel@tonic-gate 
53360Sstevel@tonic-gate 			/* check to see if uid/gid values are too large. */
53370Sstevel@tonic-gate 
53380Sstevel@tonic-gate 			if (srf->uid > (o_uid_t)USHRT_MAX ||
53390Sstevel@tonic-gate 			    srf->gid > (o_gid_t)USHRT_MAX) {
53400Sstevel@tonic-gate 				mutex_enter(&stp->sd_lock);
53410Sstevel@tonic-gate 				putback(stp, rdq, mp, mp->b_band);
53420Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
53430Sstevel@tonic-gate 				setf(fd, NULL);	/* release fd entry */
53440Sstevel@tonic-gate 				return (EOVERFLOW);
53450Sstevel@tonic-gate 			}
53460Sstevel@tonic-gate 
53470Sstevel@tonic-gate 			ostrfd.fd = fd;
53480Sstevel@tonic-gate 			ostrfd.uid = (o_uid_t)srf->uid;
53490Sstevel@tonic-gate 			ostrfd.gid = (o_gid_t)srf->gid;
53500Sstevel@tonic-gate 
53510Sstevel@tonic-gate 			/* Null the filler bits */
53520Sstevel@tonic-gate 			for (i = 0; i < 8; i++)
53530Sstevel@tonic-gate 				ostrfd.fill[i] = 0;
53540Sstevel@tonic-gate 
53550Sstevel@tonic-gate 			error = strcopyout(&ostrfd, (void *)arg,
53560Sstevel@tonic-gate 			    sizeof (struct o_strrecvfd), copyflag);
53570Sstevel@tonic-gate 		} else {		/* I_E_RECVFD */
53580Sstevel@tonic-gate 			struct strrecvfd	strfd;
53590Sstevel@tonic-gate 
53600Sstevel@tonic-gate 			strfd.fd = fd;
53610Sstevel@tonic-gate 			strfd.uid = srf->uid;
53620Sstevel@tonic-gate 			strfd.gid = srf->gid;
53630Sstevel@tonic-gate 
53640Sstevel@tonic-gate 			/* null the filler bits */
53650Sstevel@tonic-gate 			for (i = 0; i < 8; i++)
53660Sstevel@tonic-gate 				strfd.fill[i] = 0;
53670Sstevel@tonic-gate 
53680Sstevel@tonic-gate 			error = strcopyout(&strfd, (void *)arg,
53690Sstevel@tonic-gate 			    sizeof (struct strrecvfd), copyflag);
53700Sstevel@tonic-gate 		}
53710Sstevel@tonic-gate 
53720Sstevel@tonic-gate 		if (error) {
53730Sstevel@tonic-gate 			setf(fd, NULL);	/* release fd entry */
53740Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
53750Sstevel@tonic-gate 			putback(stp, rdq, mp, mp->b_band);
53760Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
53770Sstevel@tonic-gate 			return (error);
53780Sstevel@tonic-gate 		}
537911861SMarek.Pospisil@Sun.COM 		if (auditing) {
53800Sstevel@tonic-gate 			audit_fdrecv(fd, srf->fp);
53810Sstevel@tonic-gate 		}
53820Sstevel@tonic-gate 
53830Sstevel@tonic-gate 		/*
53840Sstevel@tonic-gate 		 * Always increment f_count since the freemsg() below will
53850Sstevel@tonic-gate 		 * always call free_passfp() which performs a closef().
53860Sstevel@tonic-gate 		 */
53870Sstevel@tonic-gate 		mutex_enter(&srf->fp->f_tlock);
53880Sstevel@tonic-gate 		srf->fp->f_count++;
53890Sstevel@tonic-gate 		mutex_exit(&srf->fp->f_tlock);
53900Sstevel@tonic-gate 		setf(fd, srf->fp);
53910Sstevel@tonic-gate 		freemsg(mp);
53920Sstevel@tonic-gate 		return (0);
53935753Sgww 	}
53940Sstevel@tonic-gate 
53950Sstevel@tonic-gate 	case I_SWROPT:
53960Sstevel@tonic-gate 		/*
53970Sstevel@tonic-gate 		 * Set/clear the write options. arg is a bit
53980Sstevel@tonic-gate 		 * mask with any of the following bits set...
53990Sstevel@tonic-gate 		 * 	SNDZERO - send zero length message
54000Sstevel@tonic-gate 		 *	SNDPIPE - send sigpipe to process if
54010Sstevel@tonic-gate 		 *		sd_werror is set and process is
54020Sstevel@tonic-gate 		 *		doing a write or putmsg.
54030Sstevel@tonic-gate 		 * The new stream head write options should reflect
54040Sstevel@tonic-gate 		 * what is in arg.
54050Sstevel@tonic-gate 		 */
54060Sstevel@tonic-gate 		if (arg & ~(SNDZERO|SNDPIPE))
54070Sstevel@tonic-gate 			return (EINVAL);
54080Sstevel@tonic-gate 
54090Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
54100Sstevel@tonic-gate 		stp->sd_wput_opt &= ~(SW_SIGPIPE|SW_SNDZERO);
54110Sstevel@tonic-gate 		if (arg & SNDZERO)
54120Sstevel@tonic-gate 			stp->sd_wput_opt |= SW_SNDZERO;
54130Sstevel@tonic-gate 		if (arg & SNDPIPE)
54140Sstevel@tonic-gate 			stp->sd_wput_opt |= SW_SIGPIPE;
54150Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
54160Sstevel@tonic-gate 		return (0);
54170Sstevel@tonic-gate 
54180Sstevel@tonic-gate 	case I_GWROPT:
54195753Sgww 	{
54200Sstevel@tonic-gate 		int wropt = 0;
54210Sstevel@tonic-gate 
54220Sstevel@tonic-gate 		if (stp->sd_wput_opt & SW_SNDZERO)
54230Sstevel@tonic-gate 			wropt |= SNDZERO;
54240Sstevel@tonic-gate 		if (stp->sd_wput_opt & SW_SIGPIPE)
54250Sstevel@tonic-gate 			wropt |= SNDPIPE;
54260Sstevel@tonic-gate 		return (strcopyout(&wropt, (void *)arg, sizeof (wropt),
54270Sstevel@tonic-gate 		    copyflag));
54285753Sgww 	}
54290Sstevel@tonic-gate 
54300Sstevel@tonic-gate 	case I_LIST:
54310Sstevel@tonic-gate 		/*
54320Sstevel@tonic-gate 		 * Returns all the modules found on this stream,
54330Sstevel@tonic-gate 		 * upto the driver. If argument is NULL, return the
54340Sstevel@tonic-gate 		 * number of modules (including driver). If argument
54350Sstevel@tonic-gate 		 * is not NULL, copy the names into the structure
54360Sstevel@tonic-gate 		 * provided.
54370Sstevel@tonic-gate 		 */
54380Sstevel@tonic-gate 
54395753Sgww 	{
54400Sstevel@tonic-gate 		queue_t *q;
54418752SPeter.Memishian@Sun.COM 		char *qname;
54428752SPeter.Memishian@Sun.COM 		int i, nmods;
54438752SPeter.Memishian@Sun.COM 		struct str_mlist *mlist;
54440Sstevel@tonic-gate 		STRUCT_DECL(str_list, strlist);
54450Sstevel@tonic-gate 
54460Sstevel@tonic-gate 		if (arg == NULL) { /* Return number of modules plus driver */
54478752SPeter.Memishian@Sun.COM 			if (stp->sd_vnode->v_type == VFIFO)
54480Sstevel@tonic-gate 				*rvalp = stp->sd_pushcnt;
54498752SPeter.Memishian@Sun.COM 			else
54500Sstevel@tonic-gate 				*rvalp = stp->sd_pushcnt + 1;
54518752SPeter.Memishian@Sun.COM 			return (0);
54528752SPeter.Memishian@Sun.COM 		}
54538752SPeter.Memishian@Sun.COM 
54548752SPeter.Memishian@Sun.COM 		STRUCT_INIT(strlist, flag);
54558752SPeter.Memishian@Sun.COM 
54568752SPeter.Memishian@Sun.COM 		error = strcopyin((void *)arg, STRUCT_BUF(strlist),
54578752SPeter.Memishian@Sun.COM 		    STRUCT_SIZE(strlist), copyflag);
54588752SPeter.Memishian@Sun.COM 		if (error != 0)
54598752SPeter.Memishian@Sun.COM 			return (error);
54608752SPeter.Memishian@Sun.COM 
54618752SPeter.Memishian@Sun.COM 		mlist = STRUCT_FGETP(strlist, sl_modlist);
54628752SPeter.Memishian@Sun.COM 		nmods = STRUCT_FGET(strlist, sl_nmods);
54638752SPeter.Memishian@Sun.COM 		if (nmods <= 0)
54648752SPeter.Memishian@Sun.COM 			return (EINVAL);
54658752SPeter.Memishian@Sun.COM 
54668752SPeter.Memishian@Sun.COM 		claimstr(stp->sd_wrq);
54678752SPeter.Memishian@Sun.COM 		q = stp->sd_wrq;
54688752SPeter.Memishian@Sun.COM 		for (i = 0; i < nmods && _SAMESTR(q); i++, q = q->q_next) {
54698752SPeter.Memishian@Sun.COM 			qname = Q2NAME(q->q_next);
54708752SPeter.Memishian@Sun.COM 			error = strcopyout(qname, &mlist[i], strlen(qname) + 1,
54718752SPeter.Memishian@Sun.COM 			    copyflag);
54728752SPeter.Memishian@Sun.COM 			if (error != 0) {
54738752SPeter.Memishian@Sun.COM 				releasestr(stp->sd_wrq);
54740Sstevel@tonic-gate 				return (error);
54758752SPeter.Memishian@Sun.COM 			}
54768752SPeter.Memishian@Sun.COM 		}
54778752SPeter.Memishian@Sun.COM 		releasestr(stp->sd_wrq);
54788752SPeter.Memishian@Sun.COM 		return (strcopyout(&i, (void *)arg, sizeof (int), copyflag));
54795753Sgww 	}
54800Sstevel@tonic-gate 
54810Sstevel@tonic-gate 	case I_CKBAND:
54825753Sgww 	{
54830Sstevel@tonic-gate 		queue_t *q;
54840Sstevel@tonic-gate 		qband_t *qbp;
54850Sstevel@tonic-gate 
54860Sstevel@tonic-gate 		if ((arg < 0) || (arg >= NBAND))
54870Sstevel@tonic-gate 			return (EINVAL);
54880Sstevel@tonic-gate 		q = _RD(stp->sd_wrq);
54890Sstevel@tonic-gate 		mutex_enter(QLOCK(q));
54900Sstevel@tonic-gate 		if (arg > (int)q->q_nband) {
54910Sstevel@tonic-gate 			*rvalp = 0;
54920Sstevel@tonic-gate 		} else {
54930Sstevel@tonic-gate 			if (arg == 0) {
54940Sstevel@tonic-gate 				if (q->q_first)
54950Sstevel@tonic-gate 					*rvalp = 1;
54960Sstevel@tonic-gate 				else
54970Sstevel@tonic-gate 					*rvalp = 0;
54980Sstevel@tonic-gate 			} else {
54990Sstevel@tonic-gate 				qbp = q->q_bandp;
55000Sstevel@tonic-gate 				while (--arg > 0)
55010Sstevel@tonic-gate 					qbp = qbp->qb_next;
55020Sstevel@tonic-gate 				if (qbp->qb_first)
55030Sstevel@tonic-gate 					*rvalp = 1;
55040Sstevel@tonic-gate 				else
55050Sstevel@tonic-gate 					*rvalp = 0;
55060Sstevel@tonic-gate 			}
55070Sstevel@tonic-gate 		}
55080Sstevel@tonic-gate 		mutex_exit(QLOCK(q));
55090Sstevel@tonic-gate 		return (0);
55105753Sgww 	}
55110Sstevel@tonic-gate 
55120Sstevel@tonic-gate 	case I_GETBAND:
55135753Sgww 	{
55140Sstevel@tonic-gate 		int intpri;
55150Sstevel@tonic-gate 		queue_t *q;
55160Sstevel@tonic-gate 
55170Sstevel@tonic-gate 		q = _RD(stp->sd_wrq);
55180Sstevel@tonic-gate 		mutex_enter(QLOCK(q));
55190Sstevel@tonic-gate 		mp = q->q_first;
55200Sstevel@tonic-gate 		if (!mp) {
55210Sstevel@tonic-gate 			mutex_exit(QLOCK(q));
55220Sstevel@tonic-gate 			return (ENODATA);
55230Sstevel@tonic-gate 		}
55240Sstevel@tonic-gate 		intpri = (int)mp->b_band;
55250Sstevel@tonic-gate 		error = strcopyout(&intpri, (void *)arg, sizeof (int),
55260Sstevel@tonic-gate 		    copyflag);
55270Sstevel@tonic-gate 		mutex_exit(QLOCK(q));
55280Sstevel@tonic-gate 		return (error);
55295753Sgww 	}
55300Sstevel@tonic-gate 
55310Sstevel@tonic-gate 	case I_ATMARK:
55325753Sgww 	{
55330Sstevel@tonic-gate 		queue_t *q;
55340Sstevel@tonic-gate 
55350Sstevel@tonic-gate 		if (arg & ~(ANYMARK|LASTMARK))
55360Sstevel@tonic-gate 			return (EINVAL);
55370Sstevel@tonic-gate 		q = _RD(stp->sd_wrq);
55380Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
55390Sstevel@tonic-gate 		if ((stp->sd_flag & STRATMARK) && (arg == ANYMARK)) {
55400Sstevel@tonic-gate 			*rvalp = 1;
55410Sstevel@tonic-gate 		} else {
55420Sstevel@tonic-gate 			mutex_enter(QLOCK(q));
55430Sstevel@tonic-gate 			mp = q->q_first;
55440Sstevel@tonic-gate 
55450Sstevel@tonic-gate 			if (mp == NULL)
55460Sstevel@tonic-gate 				*rvalp = 0;
55470Sstevel@tonic-gate 			else if ((arg == ANYMARK) && (mp->b_flag & MSGMARK))
55480Sstevel@tonic-gate 				*rvalp = 1;
55490Sstevel@tonic-gate 			else if ((arg == LASTMARK) && (mp == stp->sd_mark))
55500Sstevel@tonic-gate 				*rvalp = 1;
55510Sstevel@tonic-gate 			else
55520Sstevel@tonic-gate 				*rvalp = 0;
55530Sstevel@tonic-gate 			mutex_exit(QLOCK(q));
55540Sstevel@tonic-gate 		}
55550Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
55560Sstevel@tonic-gate 		return (0);
55575753Sgww 	}
55580Sstevel@tonic-gate 
55590Sstevel@tonic-gate 	case I_CANPUT:
55605753Sgww 	{
55610Sstevel@tonic-gate 		char band;
55620Sstevel@tonic-gate 
55630Sstevel@tonic-gate 		if ((arg < 0) || (arg >= NBAND))
55640Sstevel@tonic-gate 			return (EINVAL);
55650Sstevel@tonic-gate 		band = (char)arg;
55660Sstevel@tonic-gate 		*rvalp = bcanputnext(stp->sd_wrq, band);
55670Sstevel@tonic-gate 		return (0);
55685753Sgww 	}
55690Sstevel@tonic-gate 
55700Sstevel@tonic-gate 	case I_SETCLTIME:
55715753Sgww 	{
55720Sstevel@tonic-gate 		int closetime;
55730Sstevel@tonic-gate 
55740Sstevel@tonic-gate 		error = strcopyin((void *)arg, &closetime, sizeof (int),
55750Sstevel@tonic-gate 		    copyflag);
55760Sstevel@tonic-gate 		if (error)
55770Sstevel@tonic-gate 			return (error);
55780Sstevel@tonic-gate 		if (closetime < 0)
55790Sstevel@tonic-gate 			return (EINVAL);
55800Sstevel@tonic-gate 
55810Sstevel@tonic-gate 		stp->sd_closetime = closetime;
55820Sstevel@tonic-gate 		return (0);
55835753Sgww 	}
55840Sstevel@tonic-gate 
55850Sstevel@tonic-gate 	case I_GETCLTIME:
55865753Sgww 	{
55870Sstevel@tonic-gate 		int closetime;
55880Sstevel@tonic-gate 
55890Sstevel@tonic-gate 		closetime = stp->sd_closetime;
55900Sstevel@tonic-gate 		return (strcopyout(&closetime, (void *)arg, sizeof (int),
55910Sstevel@tonic-gate 		    copyflag));
55925753Sgww 	}
55930Sstevel@tonic-gate 
55940Sstevel@tonic-gate 	case TIOCGSID:
55950Sstevel@tonic-gate 	{
55960Sstevel@tonic-gate 		pid_t sid;
55970Sstevel@tonic-gate 
55982712Snn35248 		mutex_enter(&stp->sd_lock);
55990Sstevel@tonic-gate 		if (stp->sd_sidp == NULL) {
56002712Snn35248 			mutex_exit(&stp->sd_lock);
56010Sstevel@tonic-gate 			return (ENOTTY);
56020Sstevel@tonic-gate 		}
56030Sstevel@tonic-gate 		sid = stp->sd_sidp->pid_id;
56042712Snn35248 		mutex_exit(&stp->sd_lock);
56050Sstevel@tonic-gate 		return (strcopyout(&sid, (void *)arg, sizeof (pid_t),
56060Sstevel@tonic-gate 		    copyflag));
56070Sstevel@tonic-gate 	}
56080Sstevel@tonic-gate 
56090Sstevel@tonic-gate 	case TIOCSPGRP:
56100Sstevel@tonic-gate 	{
56110Sstevel@tonic-gate 		pid_t pgrp;
56120Sstevel@tonic-gate 		proc_t *q;
56130Sstevel@tonic-gate 		pid_t	sid, fg_pgid, bg_pgid;
56140Sstevel@tonic-gate 
56150Sstevel@tonic-gate 		if (error = strcopyin((void *)arg, &pgrp, sizeof (pid_t),
56160Sstevel@tonic-gate 		    copyflag))
56170Sstevel@tonic-gate 			return (error);
56180Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
56190Sstevel@tonic-gate 		mutex_enter(&pidlock);
56200Sstevel@tonic-gate 		if (stp->sd_sidp != ttoproc(curthread)->p_sessp->s_sidp) {
56210Sstevel@tonic-gate 			mutex_exit(&pidlock);
56220Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
56230Sstevel@tonic-gate 			return (ENOTTY);
56240Sstevel@tonic-gate 		}
56250Sstevel@tonic-gate 		if (pgrp == stp->sd_pgidp->pid_id) {
56260Sstevel@tonic-gate 			mutex_exit(&pidlock);
56270Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
56280Sstevel@tonic-gate 			return (0);
56290Sstevel@tonic-gate 		}
56300Sstevel@tonic-gate 		if (pgrp <= 0 || pgrp >= maxpid) {
56310Sstevel@tonic-gate 			mutex_exit(&pidlock);
56320Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
56330Sstevel@tonic-gate 			return (EINVAL);
56340Sstevel@tonic-gate 		}
56350Sstevel@tonic-gate 		if ((q = pgfind(pgrp)) == NULL ||
56360Sstevel@tonic-gate 		    q->p_sessp != ttoproc(curthread)->p_sessp) {
56370Sstevel@tonic-gate 			mutex_exit(&pidlock);
56380Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
56390Sstevel@tonic-gate 			return (EPERM);
56400Sstevel@tonic-gate 		}
56410Sstevel@tonic-gate 		sid = stp->sd_sidp->pid_id;
56420Sstevel@tonic-gate 		fg_pgid = q->p_pgrp;
56430Sstevel@tonic-gate 		bg_pgid = stp->sd_pgidp->pid_id;
56440Sstevel@tonic-gate 		CL_SET_PROCESS_GROUP(curthread, sid, bg_pgid, fg_pgid);
56450Sstevel@tonic-gate 		PID_RELE(stp->sd_pgidp);
56462712Snn35248 		ctty_clear_sighuped();
56470Sstevel@tonic-gate 		stp->sd_pgidp = q->p_pgidp;
56480Sstevel@tonic-gate 		PID_HOLD(stp->sd_pgidp);
56490Sstevel@tonic-gate 		mutex_exit(&pidlock);
56500Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
56510Sstevel@tonic-gate 		return (0);
56520Sstevel@tonic-gate 	}
56530Sstevel@tonic-gate 
56540Sstevel@tonic-gate 	case TIOCGPGRP:
56550Sstevel@tonic-gate 	{
56560Sstevel@tonic-gate 		pid_t pgrp;
56570Sstevel@tonic-gate 
56582712Snn35248 		mutex_enter(&stp->sd_lock);
56590Sstevel@tonic-gate 		if (stp->sd_sidp == NULL) {
56602712Snn35248 			mutex_exit(&stp->sd_lock);
56610Sstevel@tonic-gate 			return (ENOTTY);
56620Sstevel@tonic-gate 		}
56630Sstevel@tonic-gate 		pgrp = stp->sd_pgidp->pid_id;
56642712Snn35248 		mutex_exit(&stp->sd_lock);
56650Sstevel@tonic-gate 		return (strcopyout(&pgrp, (void *)arg, sizeof (pid_t),
56660Sstevel@tonic-gate 		    copyflag));
56670Sstevel@tonic-gate 	}
56680Sstevel@tonic-gate 
56692712Snn35248 	case TIOCSCTTY:
56702712Snn35248 	{
56712712Snn35248 		return (strctty(stp));
56722712Snn35248 	}
56732712Snn35248 
56742712Snn35248 	case TIOCNOTTY:
56752712Snn35248 	{
56762712Snn35248 		/* freectty() always assumes curproc. */
56772712Snn35248 		if (freectty(B_FALSE) != 0)
56782712Snn35248 			return (0);
56792712Snn35248 		return (ENOTTY);
56802712Snn35248 	}
56812712Snn35248 
56820Sstevel@tonic-gate 	case FIONBIO:
56830Sstevel@tonic-gate 	case FIOASYNC:
56840Sstevel@tonic-gate 		return (0);	/* handled by the upper layer */
56850Sstevel@tonic-gate 	}
56860Sstevel@tonic-gate }
56870Sstevel@tonic-gate 
56880Sstevel@tonic-gate /*
56890Sstevel@tonic-gate  * Custom free routine used for M_PASSFP messages.
56900Sstevel@tonic-gate  */
56910Sstevel@tonic-gate static void
free_passfp(struct k_strrecvfd * srf)56920Sstevel@tonic-gate free_passfp(struct k_strrecvfd *srf)
56930Sstevel@tonic-gate {
56940Sstevel@tonic-gate 	(void) closef(srf->fp);
56950Sstevel@tonic-gate 	kmem_free(srf, sizeof (struct k_strrecvfd) + sizeof (frtn_t));
56960Sstevel@tonic-gate }
56970Sstevel@tonic-gate 
56980Sstevel@tonic-gate /* ARGSUSED */
56990Sstevel@tonic-gate int
do_sendfp(struct stdata * stp,struct file * fp,struct cred * cr)57000Sstevel@tonic-gate do_sendfp(struct stdata *stp, struct file *fp, struct cred *cr)
57010Sstevel@tonic-gate {
57020Sstevel@tonic-gate 	queue_t *qp, *nextqp;
57030Sstevel@tonic-gate 	struct k_strrecvfd *srf;
57040Sstevel@tonic-gate 	mblk_t *mp;
57050Sstevel@tonic-gate 	frtn_t *frtnp;
57060Sstevel@tonic-gate 	size_t bufsize;
57070Sstevel@tonic-gate 	queue_t	*mate = NULL;
57080Sstevel@tonic-gate 	syncq_t	*sq = NULL;
57090Sstevel@tonic-gate 	int retval = 0;
57100Sstevel@tonic-gate 
57110Sstevel@tonic-gate 	if (stp->sd_flag & STRHUP)
57120Sstevel@tonic-gate 		return (ENXIO);
57130Sstevel@tonic-gate 
57140Sstevel@tonic-gate 	claimstr(stp->sd_wrq);
57150Sstevel@tonic-gate 
57160Sstevel@tonic-gate 	/* Fastpath, we have a pipe, and we are already mated, use it. */
57170Sstevel@tonic-gate 	if (STRMATED(stp)) {
57180Sstevel@tonic-gate 		qp = _RD(stp->sd_mate->sd_wrq);
57190Sstevel@tonic-gate 		claimstr(qp);
57200Sstevel@tonic-gate 		mate = qp;
57210Sstevel@tonic-gate 	} else { /* Not already mated. */
57220Sstevel@tonic-gate 
57230Sstevel@tonic-gate 		/*
57240Sstevel@tonic-gate 		 * Walk the stream to the end of this one.
57250Sstevel@tonic-gate 		 * assumes that the claimstr() will prevent
57260Sstevel@tonic-gate 		 * plumbing between the stream head and the
57270Sstevel@tonic-gate 		 * driver from changing
57280Sstevel@tonic-gate 		 */
57290Sstevel@tonic-gate 		qp = stp->sd_wrq;
57300Sstevel@tonic-gate 
57310Sstevel@tonic-gate 		/*
57320Sstevel@tonic-gate 		 * Loop until we reach the end of this stream.
57330Sstevel@tonic-gate 		 * On completion, qp points to the write queue
57340Sstevel@tonic-gate 		 * at the end of the stream, or the read queue
57350Sstevel@tonic-gate 		 * at the stream head if this is a fifo.
57360Sstevel@tonic-gate 		 */
57370Sstevel@tonic-gate 		while (((qp = qp->q_next) != NULL) && _SAMESTR(qp))
57380Sstevel@tonic-gate 			;
57390Sstevel@tonic-gate 
57400Sstevel@tonic-gate 		/*
57410Sstevel@tonic-gate 		 * Just in case we get a q_next which is NULL, but
57420Sstevel@tonic-gate 		 * not at the end of the stream.  This is actually
57430Sstevel@tonic-gate 		 * broken, so we set an assert to catch it in
57440Sstevel@tonic-gate 		 * debug, and set an error and return if not debug.
57450Sstevel@tonic-gate 		 */
57460Sstevel@tonic-gate 		ASSERT(qp);
57470Sstevel@tonic-gate 		if (qp == NULL) {
57480Sstevel@tonic-gate 			releasestr(stp->sd_wrq);
57490Sstevel@tonic-gate 			return (EINVAL);
57500Sstevel@tonic-gate 		}
57510Sstevel@tonic-gate 
57520Sstevel@tonic-gate 		/*
57530Sstevel@tonic-gate 		 * Enter the syncq for the driver, so (hopefully)
57540Sstevel@tonic-gate 		 * the queue values will not change on us.
57550Sstevel@tonic-gate 		 * XXXX - This will only prevent the race IFF only
57560Sstevel@tonic-gate 		 *   the write side modifies the q_next member, and
57570Sstevel@tonic-gate 		 *   the put procedure is protected by at least
57580Sstevel@tonic-gate 		 *   MT_PERQ.
57590Sstevel@tonic-gate 		 */
57600Sstevel@tonic-gate 		if ((sq = qp->q_syncq) != NULL)
57610Sstevel@tonic-gate 			entersq(sq, SQ_PUT);
57620Sstevel@tonic-gate 
57630Sstevel@tonic-gate 		/* Now get the q_next value from this qp. */
57640Sstevel@tonic-gate 		nextqp = qp->q_next;
57650Sstevel@tonic-gate 
57660Sstevel@tonic-gate 		/*
57670Sstevel@tonic-gate 		 * If nextqp exists and the other stream is different
57680Sstevel@tonic-gate 		 * from this one claim the stream, set the mate, and
57690Sstevel@tonic-gate 		 * get the read queue at the stream head of the other
57700Sstevel@tonic-gate 		 * stream.  Assumes that nextqp was at least valid when
57710Sstevel@tonic-gate 		 * we got it.  Hopefully the entersq of the driver
57720Sstevel@tonic-gate 		 * will prevent it from changing on us.
57730Sstevel@tonic-gate 		 */
57740Sstevel@tonic-gate 		if ((nextqp != NULL) && (STREAM(nextqp) != stp)) {
57750Sstevel@tonic-gate 			ASSERT(qp->q_qinfo->qi_srvp);
57760Sstevel@tonic-gate 			ASSERT(_OTHERQ(qp)->q_qinfo->qi_srvp);
57770Sstevel@tonic-gate 			ASSERT(_OTHERQ(qp->q_next)->q_qinfo->qi_srvp);
57780Sstevel@tonic-gate 			claimstr(nextqp);
57790Sstevel@tonic-gate 
57800Sstevel@tonic-gate 			/* Make sure we still have a q_next */
57810Sstevel@tonic-gate 			if (nextqp != qp->q_next) {
57820Sstevel@tonic-gate 				releasestr(stp->sd_wrq);
57830Sstevel@tonic-gate 				releasestr(nextqp);
57840Sstevel@tonic-gate 				return (EINVAL);
57850Sstevel@tonic-gate 			}
57860Sstevel@tonic-gate 
57870Sstevel@tonic-gate 			qp = _RD(STREAM(nextqp)->sd_wrq);
57880Sstevel@tonic-gate 			mate = qp;
57890Sstevel@tonic-gate 		}
57900Sstevel@tonic-gate 		/* If we entered the synq above, leave it. */
57910Sstevel@tonic-gate 		if (sq != NULL)
57920Sstevel@tonic-gate 			leavesq(sq, SQ_PUT);
57930Sstevel@tonic-gate 	} /*  STRMATED(STP)  */
57940Sstevel@tonic-gate 
57950Sstevel@tonic-gate 	/* XXX prevents substitution of the ops vector */
57960Sstevel@tonic-gate 	if (qp->q_qinfo != &strdata && qp->q_qinfo != &fifo_strdata) {
57970Sstevel@tonic-gate 		retval = EINVAL;
57980Sstevel@tonic-gate 		goto out;
57990Sstevel@tonic-gate 	}
58000Sstevel@tonic-gate 
58010Sstevel@tonic-gate 	if (qp->q_flag & QFULL) {
58020Sstevel@tonic-gate 		retval = EAGAIN;
58030Sstevel@tonic-gate 		goto out;
58040Sstevel@tonic-gate 	}
58050Sstevel@tonic-gate 
58060Sstevel@tonic-gate 	/*
58070Sstevel@tonic-gate 	 * Since M_PASSFP messages include a file descriptor, we use
58080Sstevel@tonic-gate 	 * esballoc() and specify a custom free routine (free_passfp()) that
58090Sstevel@tonic-gate 	 * will close the descriptor as part of freeing the message.  For
58100Sstevel@tonic-gate 	 * convenience, we stash the frtn_t right after the data block.
58110Sstevel@tonic-gate 	 */
58120Sstevel@tonic-gate 	bufsize = sizeof (struct k_strrecvfd) + sizeof (frtn_t);
58130Sstevel@tonic-gate 	srf = kmem_alloc(bufsize, KM_NOSLEEP);
58140Sstevel@tonic-gate 	if (srf == NULL) {
58150Sstevel@tonic-gate 		retval = EAGAIN;
58160Sstevel@tonic-gate 		goto out;
58170Sstevel@tonic-gate 	}
58180Sstevel@tonic-gate 
58190Sstevel@tonic-gate 	frtnp = (frtn_t *)(srf + 1);
58200Sstevel@tonic-gate 	frtnp->free_arg = (caddr_t)srf;
58210Sstevel@tonic-gate 	frtnp->free_func = free_passfp;
58220Sstevel@tonic-gate 
58230Sstevel@tonic-gate 	mp = esballoc((uchar_t *)srf, bufsize, BPRI_MED, frtnp);
58240Sstevel@tonic-gate 	if (mp == NULL) {
58250Sstevel@tonic-gate 		kmem_free(srf, bufsize);
58260Sstevel@tonic-gate 		retval = EAGAIN;
58270Sstevel@tonic-gate 		goto out;
58280Sstevel@tonic-gate 	}
58290Sstevel@tonic-gate 	mp->b_wptr += sizeof (struct k_strrecvfd);
58300Sstevel@tonic-gate 	mp->b_datap->db_type = M_PASSFP;
58310Sstevel@tonic-gate 
58320Sstevel@tonic-gate 	srf->fp = fp;
58330Sstevel@tonic-gate 	srf->uid = crgetuid(curthread->t_cred);
58340Sstevel@tonic-gate 	srf->gid = crgetgid(curthread->t_cred);
58350Sstevel@tonic-gate 	mutex_enter(&fp->f_tlock);
58360Sstevel@tonic-gate 	fp->f_count++;
58370Sstevel@tonic-gate 	mutex_exit(&fp->f_tlock);
58380Sstevel@tonic-gate 
58390Sstevel@tonic-gate 	put(qp, mp);
58400Sstevel@tonic-gate out:
58410Sstevel@tonic-gate 	releasestr(stp->sd_wrq);
58420Sstevel@tonic-gate 	if (mate)
58430Sstevel@tonic-gate 		releasestr(mate);
58440Sstevel@tonic-gate 	return (retval);
58450Sstevel@tonic-gate }
58460Sstevel@tonic-gate 
58470Sstevel@tonic-gate /*
58480Sstevel@tonic-gate  * Send an ioctl message downstream and wait for acknowledgement.
58490Sstevel@tonic-gate  * flags may be set to either U_TO_K or K_TO_K and a combination
58500Sstevel@tonic-gate  * of STR_NOERROR or STR_NOSIG
58510Sstevel@tonic-gate  * STR_NOSIG: Signals are essentially ignored or held and have
58520Sstevel@tonic-gate  *	no effect for the duration of the call.
58530Sstevel@tonic-gate  * STR_NOERROR: Ignores stream head read, write and hup errors.
58540Sstevel@tonic-gate  *	Additionally, if an existing ioctl times out, it is assumed
58550Sstevel@tonic-gate  *	lost and and this ioctl will continue as if the previous ioctl had
58560Sstevel@tonic-gate  *	finished.  ETIME may be returned if this ioctl times out (i.e.
58570Sstevel@tonic-gate  *	ic_timout is not INFTIM).  Non-stream head errors may be returned if
58580Sstevel@tonic-gate  *	the ioc_error indicates that the driver/module had problems,
58590Sstevel@tonic-gate  *	an EFAULT was found when accessing user data, a lack of
58600Sstevel@tonic-gate  * 	resources, etc.
58610Sstevel@tonic-gate  */
58620Sstevel@tonic-gate int
strdoioctl(struct stdata * stp,struct strioctl * strioc,int fflags,int flag,cred_t * crp,int * rvalp)58630Sstevel@tonic-gate strdoioctl(
58640Sstevel@tonic-gate 	struct stdata *stp,
58650Sstevel@tonic-gate 	struct strioctl *strioc,
58660Sstevel@tonic-gate 	int fflags,		/* file flags with model info */
58670Sstevel@tonic-gate 	int flag,
58680Sstevel@tonic-gate 	cred_t *crp,
58690Sstevel@tonic-gate 	int *rvalp)
58700Sstevel@tonic-gate {
58710Sstevel@tonic-gate 	mblk_t *bp;
58720Sstevel@tonic-gate 	struct iocblk *iocbp;
58730Sstevel@tonic-gate 	struct copyreq *reqp;
58740Sstevel@tonic-gate 	struct copyresp *resp;
58750Sstevel@tonic-gate 	int id;
58760Sstevel@tonic-gate 	int transparent = 0;
58770Sstevel@tonic-gate 	int error = 0;
58780Sstevel@tonic-gate 	int len = 0;
58790Sstevel@tonic-gate 	caddr_t taddr;
58800Sstevel@tonic-gate 	int copyflag = (flag & (U_TO_K | K_TO_K));
58810Sstevel@tonic-gate 	int sigflag = (flag & STR_NOSIG);
58820Sstevel@tonic-gate 	int errs;
58830Sstevel@tonic-gate 	uint_t waitflags;
5884*12602Sanil.udupa@sun.com 	boolean_t set_iocwaitne = B_FALSE;
58850Sstevel@tonic-gate 
58860Sstevel@tonic-gate 	ASSERT(copyflag == U_TO_K || copyflag == K_TO_K);
58870Sstevel@tonic-gate 	ASSERT((fflags & FMODELS) != 0);
58880Sstevel@tonic-gate 
58890Sstevel@tonic-gate 	TRACE_2(TR_FAC_STREAMS_FR,
58905753Sgww 	    TR_STRDOIOCTL,
58915753Sgww 	    "strdoioctl:stp %p strioc %p", stp, strioc);
58920Sstevel@tonic-gate 	if (strioc->ic_len == TRANSPARENT) {	/* send arg in M_DATA block */
58930Sstevel@tonic-gate 		transparent = 1;
58940Sstevel@tonic-gate 		strioc->ic_len = sizeof (intptr_t);
58950Sstevel@tonic-gate 	}
58960Sstevel@tonic-gate 
58970Sstevel@tonic-gate 	if (strioc->ic_len < 0 || (strmsgsz > 0 && strioc->ic_len > strmsgsz))
58980Sstevel@tonic-gate 		return (EINVAL);
58990Sstevel@tonic-gate 
59000Sstevel@tonic-gate 	if ((bp = allocb_cred_wait(sizeof (union ioctypes), sigflag, &error,
59018778SErik.Nordmark@Sun.COM 	    crp, curproc->p_pid)) == NULL)
59020Sstevel@tonic-gate 			return (error);
59030Sstevel@tonic-gate 
59040Sstevel@tonic-gate 	bzero(bp->b_wptr, sizeof (union ioctypes));
59050Sstevel@tonic-gate 
59060Sstevel@tonic-gate 	iocbp = (struct iocblk *)bp->b_wptr;
59070Sstevel@tonic-gate 	iocbp->ioc_count = strioc->ic_len;
59080Sstevel@tonic-gate 	iocbp->ioc_cmd = strioc->ic_cmd;
59090Sstevel@tonic-gate 	iocbp->ioc_flag = (fflags & FMODELS);
59100Sstevel@tonic-gate 
59110Sstevel@tonic-gate 	crhold(crp);
59120Sstevel@tonic-gate 	iocbp->ioc_cr = crp;
59130Sstevel@tonic-gate 	DB_TYPE(bp) = M_IOCTL;
59140Sstevel@tonic-gate 	bp->b_wptr += sizeof (struct iocblk);
59150Sstevel@tonic-gate 
59160Sstevel@tonic-gate 	if (flag & STR_NOERROR)
59170Sstevel@tonic-gate 		errs = STPLEX;
59180Sstevel@tonic-gate 	else
59190Sstevel@tonic-gate 		errs = STRHUP|STRDERR|STWRERR|STPLEX;
59200Sstevel@tonic-gate 
59210Sstevel@tonic-gate 	/*
59220Sstevel@tonic-gate 	 * If there is data to copy into ioctl block, do so.
59230Sstevel@tonic-gate 	 */
59240Sstevel@tonic-gate 	if (iocbp->ioc_count > 0) {
59250Sstevel@tonic-gate 		if (transparent)
59260Sstevel@tonic-gate 			/*
59270Sstevel@tonic-gate 			 * Note: STR_NOERROR does not have an effect
59280Sstevel@tonic-gate 			 * in putiocd()
59290Sstevel@tonic-gate 			 */
59300Sstevel@tonic-gate 			id = K_TO_K | sigflag;
59310Sstevel@tonic-gate 		else
59320Sstevel@tonic-gate 			id = flag;
59330Sstevel@tonic-gate 		if ((error = putiocd(bp, strioc->ic_dp, id, crp)) != 0) {
59340Sstevel@tonic-gate 			freemsg(bp);
59350Sstevel@tonic-gate 			crfree(crp);
59360Sstevel@tonic-gate 			return (error);
59370Sstevel@tonic-gate 		}
59380Sstevel@tonic-gate 
59390Sstevel@tonic-gate 		/*
59400Sstevel@tonic-gate 		 * We could have slept copying in user pages.
59410Sstevel@tonic-gate 		 * Recheck the stream head state (the other end
59420Sstevel@tonic-gate 		 * of a pipe could have gone away).
59430Sstevel@tonic-gate 		 */
59440Sstevel@tonic-gate 		if (stp->sd_flag & errs) {
59450Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
59460Sstevel@tonic-gate 			error = strgeterr(stp, errs, 0);
59470Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
59480Sstevel@tonic-gate 			if (error != 0) {
59490Sstevel@tonic-gate 				freemsg(bp);
59500Sstevel@tonic-gate 				crfree(crp);
59510Sstevel@tonic-gate 				return (error);
59520Sstevel@tonic-gate 			}
59530Sstevel@tonic-gate 		}
59540Sstevel@tonic-gate 	}
59550Sstevel@tonic-gate 	if (transparent)
59560Sstevel@tonic-gate 		iocbp->ioc_count = TRANSPARENT;
59570Sstevel@tonic-gate 
59580Sstevel@tonic-gate 	/*
59590Sstevel@tonic-gate 	 * Block for up to STRTIMOUT milliseconds if there is an outstanding
59600Sstevel@tonic-gate 	 * ioctl for this stream already running.  All processes
59610Sstevel@tonic-gate 	 * sleeping here will be awakened as a result of an ACK
59620Sstevel@tonic-gate 	 * or NAK being received for the outstanding ioctl, or
59630Sstevel@tonic-gate 	 * as a result of the timer expiring on the outstanding
59640Sstevel@tonic-gate 	 * ioctl (a failure), or as a result of any waiting
59650Sstevel@tonic-gate 	 * process's timer expiring (also a failure).
59660Sstevel@tonic-gate 	 */
59670Sstevel@tonic-gate 
59680Sstevel@tonic-gate 	error = 0;
59690Sstevel@tonic-gate 	mutex_enter(&stp->sd_lock);
5970*12602Sanil.udupa@sun.com 	while ((stp->sd_flag & IOCWAIT) ||
5971*12602Sanil.udupa@sun.com 	    (!set_iocwaitne && (stp->sd_flag & IOCWAITNE))) {
59720Sstevel@tonic-gate 		clock_t cv_rval;
59730Sstevel@tonic-gate 
59740Sstevel@tonic-gate 		TRACE_0(TR_FAC_STREAMS_FR,
59755753Sgww 		    TR_STRDOIOCTL_WAIT,
59765753Sgww 		    "strdoioctl sleeps - IOCWAIT");
59770Sstevel@tonic-gate 		cv_rval = str_cv_wait(&stp->sd_iocmonitor, &stp->sd_lock,
59780Sstevel@tonic-gate 		    STRTIMOUT, sigflag);
59790Sstevel@tonic-gate 		if (cv_rval <= 0) {
59800Sstevel@tonic-gate 			if (cv_rval == 0) {
59810Sstevel@tonic-gate 				error = EINTR;
59820Sstevel@tonic-gate 			} else {
59830Sstevel@tonic-gate 				if (flag & STR_NOERROR) {
59840Sstevel@tonic-gate 					/*
59850Sstevel@tonic-gate 					 * Terminating current ioctl in
59860Sstevel@tonic-gate 					 * progress -- assume it got lost and
59870Sstevel@tonic-gate 					 * wake up the other thread so that the
59880Sstevel@tonic-gate 					 * operation completes.
59890Sstevel@tonic-gate 					 */
59900Sstevel@tonic-gate 					if (!(stp->sd_flag & IOCWAITNE)) {
5991*12602Sanil.udupa@sun.com 						set_iocwaitne = B_TRUE;
59920Sstevel@tonic-gate 						stp->sd_flag |= IOCWAITNE;
59930Sstevel@tonic-gate 						cv_broadcast(&stp->sd_monitor);
59940Sstevel@tonic-gate 					}
59950Sstevel@tonic-gate 					/*
59960Sstevel@tonic-gate 					 * Otherwise, there's a running
59970Sstevel@tonic-gate 					 * STR_NOERROR -- we have no choice
59980Sstevel@tonic-gate 					 * here but to wait forever (or until
59990Sstevel@tonic-gate 					 * interrupted).
60000Sstevel@tonic-gate 					 */
60010Sstevel@tonic-gate 				} else {
60020Sstevel@tonic-gate 					/*
60030Sstevel@tonic-gate 					 * pending ioctl has caused
60040Sstevel@tonic-gate 					 * us to time out
60050Sstevel@tonic-gate 					 */
60060Sstevel@tonic-gate 					error = ETIME;
60070Sstevel@tonic-gate 				}
60080Sstevel@tonic-gate 			}
60090Sstevel@tonic-gate 		} else if ((stp->sd_flag & errs)) {
60100Sstevel@tonic-gate 			error = strgeterr(stp, errs, 0);
60110Sstevel@tonic-gate 		}
60120Sstevel@tonic-gate 		if (error) {
60130Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
60140Sstevel@tonic-gate 			freemsg(bp);
60150Sstevel@tonic-gate 			crfree(crp);
60160Sstevel@tonic-gate 			return (error);
60170Sstevel@tonic-gate 		}
60180Sstevel@tonic-gate 	}
60190Sstevel@tonic-gate 
60200Sstevel@tonic-gate 	/*
60210Sstevel@tonic-gate 	 * Have control of ioctl mechanism.
60220Sstevel@tonic-gate 	 * Send down ioctl packet and wait for response.
60230Sstevel@tonic-gate 	 */
60240Sstevel@tonic-gate 	if (stp->sd_iocblk != (mblk_t *)-1) {
60250Sstevel@tonic-gate 		freemsg(stp->sd_iocblk);
60260Sstevel@tonic-gate 	}
60270Sstevel@tonic-gate 	stp->sd_iocblk = NULL;
60280Sstevel@tonic-gate 
60290Sstevel@tonic-gate 	/*
60300Sstevel@tonic-gate 	 * If this is marked with 'noerror' (internal; mostly
60310Sstevel@tonic-gate 	 * I_{P,}{UN,}LINK), then make sure nobody else is able to get
60320Sstevel@tonic-gate 	 * in here by setting IOCWAITNE.
60330Sstevel@tonic-gate 	 */
60340Sstevel@tonic-gate 	waitflags = IOCWAIT;
60350Sstevel@tonic-gate 	if (flag & STR_NOERROR)
60360Sstevel@tonic-gate 		waitflags |= IOCWAITNE;
60370Sstevel@tonic-gate 
60380Sstevel@tonic-gate 	stp->sd_flag |= waitflags;
60390Sstevel@tonic-gate 
60400Sstevel@tonic-gate 	/*
60410Sstevel@tonic-gate 	 * Assign sequence number.
60420Sstevel@tonic-gate 	 */
60430Sstevel@tonic-gate 	iocbp->ioc_id = stp->sd_iocid = getiocseqno();
60440Sstevel@tonic-gate 
60450Sstevel@tonic-gate 	mutex_exit(&stp->sd_lock);
60460Sstevel@tonic-gate 
60470Sstevel@tonic-gate 	TRACE_1(TR_FAC_STREAMS_FR,
60485753Sgww 	    TR_STRDOIOCTL_PUT, "strdoioctl put: stp %p", stp);
60490Sstevel@tonic-gate 	stream_willservice(stp);
60500Sstevel@tonic-gate 	putnext(stp->sd_wrq, bp);
60510Sstevel@tonic-gate 	stream_runservice(stp);
60520Sstevel@tonic-gate 
60530Sstevel@tonic-gate 	/*
60540Sstevel@tonic-gate 	 * Timed wait for acknowledgment.  The wait time is limited by the
60550Sstevel@tonic-gate 	 * timeout value, which must be a positive integer (number of
6056898Skais 	 * milliseconds) to wait, or 0 (use default value of STRTIMOUT
60570Sstevel@tonic-gate 	 * milliseconds), or -1 (wait forever).  This will be awakened
60580Sstevel@tonic-gate 	 * either by an ACK/NAK message arriving, the timer expiring, or
60590Sstevel@tonic-gate 	 * the timer expiring on another ioctl waiting for control of the
60600Sstevel@tonic-gate 	 * mechanism.
60610Sstevel@tonic-gate 	 */
60620Sstevel@tonic-gate waitioc:
60630Sstevel@tonic-gate 	mutex_enter(&stp->sd_lock);
60640Sstevel@tonic-gate 
60650Sstevel@tonic-gate 
60660Sstevel@tonic-gate 	/*
60670Sstevel@tonic-gate 	 * If the reply has already arrived, don't sleep.  If awakened from
60680Sstevel@tonic-gate 	 * the sleep, fail only if the reply has not arrived by then.
60690Sstevel@tonic-gate 	 * Otherwise, process the reply.
60700Sstevel@tonic-gate 	 */
60710Sstevel@tonic-gate 	while (!stp->sd_iocblk) {
60720Sstevel@tonic-gate 		clock_t cv_rval;
60730Sstevel@tonic-gate 
60740Sstevel@tonic-gate 		if (stp->sd_flag & errs) {
60750Sstevel@tonic-gate 			error = strgeterr(stp, errs, 0);
60760Sstevel@tonic-gate 			if (error != 0) {
60770Sstevel@tonic-gate 				stp->sd_flag &= ~waitflags;
60780Sstevel@tonic-gate 				cv_broadcast(&stp->sd_iocmonitor);
60790Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
60800Sstevel@tonic-gate 				crfree(crp);
60810Sstevel@tonic-gate 				return (error);
60820Sstevel@tonic-gate 			}
60830Sstevel@tonic-gate 		}
60840Sstevel@tonic-gate 
60850Sstevel@tonic-gate 		TRACE_0(TR_FAC_STREAMS_FR,
60865753Sgww 		    TR_STRDOIOCTL_WAIT2,
60875753Sgww 		    "strdoioctl sleeps awaiting reply");
60880Sstevel@tonic-gate 		ASSERT(error == 0);
60890Sstevel@tonic-gate 
60900Sstevel@tonic-gate 		cv_rval = str_cv_wait(&stp->sd_monitor, &stp->sd_lock,
60910Sstevel@tonic-gate 		    (strioc->ic_timout ?
60920Sstevel@tonic-gate 		    strioc->ic_timout * 1000 : STRTIMOUT), sigflag);
60930Sstevel@tonic-gate 
60940Sstevel@tonic-gate 		/*
60950Sstevel@tonic-gate 		 * There are four possible cases here: interrupt, timeout,
60960Sstevel@tonic-gate 		 * wakeup by IOCWAITNE (above), or wakeup by strrput_nondata (a
60970Sstevel@tonic-gate 		 * valid M_IOCTL reply).
60980Sstevel@tonic-gate 		 *
60990Sstevel@tonic-gate 		 * If we've been awakened by a STR_NOERROR ioctl on some other
61000Sstevel@tonic-gate 		 * thread, then sd_iocblk will still be NULL, and IOCWAITNE
61010Sstevel@tonic-gate 		 * will be set.  Pretend as if we just timed out.  Note that
61020Sstevel@tonic-gate 		 * this other thread waited at least STRTIMOUT before trying to
61030Sstevel@tonic-gate 		 * awaken our thread, so this is indistinguishable (even for
61040Sstevel@tonic-gate 		 * INFTIM) from the case where we failed with ETIME waiting on
61050Sstevel@tonic-gate 		 * IOCWAIT in the prior loop.
61060Sstevel@tonic-gate 		 */
61070Sstevel@tonic-gate 		if (cv_rval > 0 && !(flag & STR_NOERROR) &&
61080Sstevel@tonic-gate 		    stp->sd_iocblk == NULL && (stp->sd_flag & IOCWAITNE)) {
61090Sstevel@tonic-gate 			cv_rval = -1;
61100Sstevel@tonic-gate 		}
61110Sstevel@tonic-gate 
61120Sstevel@tonic-gate 		/*
61130Sstevel@tonic-gate 		 * note: STR_NOERROR does not protect
61140Sstevel@tonic-gate 		 * us here.. use ic_timout < 0
61150Sstevel@tonic-gate 		 */
61160Sstevel@tonic-gate 		if (cv_rval <= 0) {
61170Sstevel@tonic-gate 			if (cv_rval == 0) {
61180Sstevel@tonic-gate 				error = EINTR;
61190Sstevel@tonic-gate 			} else {
61200Sstevel@tonic-gate 				error =  ETIME;
61210Sstevel@tonic-gate 			}
61220Sstevel@tonic-gate 			/*
61230Sstevel@tonic-gate 			 * A message could have come in after we were scheduled
61240Sstevel@tonic-gate 			 * but before we were actually run.
61250Sstevel@tonic-gate 			 */
61260Sstevel@tonic-gate 			bp = stp->sd_iocblk;
61270Sstevel@tonic-gate 			stp->sd_iocblk = NULL;
61280Sstevel@tonic-gate 			if (bp != NULL) {
61290Sstevel@tonic-gate 				if ((bp->b_datap->db_type == M_COPYIN) ||
61300Sstevel@tonic-gate 				    (bp->b_datap->db_type == M_COPYOUT)) {
61310Sstevel@tonic-gate 					mutex_exit(&stp->sd_lock);
61320Sstevel@tonic-gate 					if (bp->b_cont) {
61330Sstevel@tonic-gate 						freemsg(bp->b_cont);
61340Sstevel@tonic-gate 						bp->b_cont = NULL;
61350Sstevel@tonic-gate 					}
61360Sstevel@tonic-gate 					bp->b_datap->db_type = M_IOCDATA;
61370Sstevel@tonic-gate 					bp->b_wptr = bp->b_rptr +
61385753Sgww 					    sizeof (struct copyresp);
61390Sstevel@tonic-gate 					resp = (struct copyresp *)bp->b_rptr;
61400Sstevel@tonic-gate 					resp->cp_rval =
61410Sstevel@tonic-gate 					    (caddr_t)1; /* failure */
61420Sstevel@tonic-gate 					stream_willservice(stp);
61430Sstevel@tonic-gate 					putnext(stp->sd_wrq, bp);
61440Sstevel@tonic-gate 					stream_runservice(stp);
61450Sstevel@tonic-gate 					mutex_enter(&stp->sd_lock);
61460Sstevel@tonic-gate 				} else {
61470Sstevel@tonic-gate 					freemsg(bp);
61480Sstevel@tonic-gate 				}
61490Sstevel@tonic-gate 			}
61500Sstevel@tonic-gate 			stp->sd_flag &= ~waitflags;
61510Sstevel@tonic-gate 			cv_broadcast(&stp->sd_iocmonitor);
61520Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
61530Sstevel@tonic-gate 			crfree(crp);
61540Sstevel@tonic-gate 			return (error);
61550Sstevel@tonic-gate 		}
61560Sstevel@tonic-gate 	}
61570Sstevel@tonic-gate 	bp = stp->sd_iocblk;
61580Sstevel@tonic-gate 	/*
61590Sstevel@tonic-gate 	 * Note: it is strictly impossible to get here with sd_iocblk set to
61600Sstevel@tonic-gate 	 * -1.  This is because the initial loop above doesn't allow any new
61610Sstevel@tonic-gate 	 * ioctls into the fray until all others have passed this point.
61620Sstevel@tonic-gate 	 */
61630Sstevel@tonic-gate 	ASSERT(bp != NULL && bp != (mblk_t *)-1);
61640Sstevel@tonic-gate 	TRACE_1(TR_FAC_STREAMS_FR,
61655753Sgww 	    TR_STRDOIOCTL_ACK, "strdoioctl got reply: bp %p", bp);
61660Sstevel@tonic-gate 	if ((bp->b_datap->db_type == M_IOCACK) ||
61670Sstevel@tonic-gate 	    (bp->b_datap->db_type == M_IOCNAK)) {
61680Sstevel@tonic-gate 		/* for detection of duplicate ioctl replies */
61690Sstevel@tonic-gate 		stp->sd_iocblk = (mblk_t *)-1;
61700Sstevel@tonic-gate 		stp->sd_flag &= ~waitflags;
61710Sstevel@tonic-gate 		cv_broadcast(&stp->sd_iocmonitor);
61720Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
61730Sstevel@tonic-gate 	} else {
61740Sstevel@tonic-gate 		/*
61750Sstevel@tonic-gate 		 * flags not cleared here because we're still doing
61760Sstevel@tonic-gate 		 * copy in/out for ioctl.
61770Sstevel@tonic-gate 		 */
61780Sstevel@tonic-gate 		stp->sd_iocblk = NULL;
61790Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
61800Sstevel@tonic-gate 	}
61810Sstevel@tonic-gate 
61820Sstevel@tonic-gate 
61830Sstevel@tonic-gate 	/*
61840Sstevel@tonic-gate 	 * Have received acknowledgment.
61850Sstevel@tonic-gate 	 */
61860Sstevel@tonic-gate 
61870Sstevel@tonic-gate 	switch (bp->b_datap->db_type) {
61880Sstevel@tonic-gate 	case M_IOCACK:
61890Sstevel@tonic-gate 		/*
61900Sstevel@tonic-gate 		 * Positive ack.
61910Sstevel@tonic-gate 		 */
61920Sstevel@tonic-gate 		iocbp = (struct iocblk *)bp->b_rptr;
61930Sstevel@tonic-gate 
61940Sstevel@tonic-gate 		/*
61950Sstevel@tonic-gate 		 * Set error if indicated.
61960Sstevel@tonic-gate 		 */
61970Sstevel@tonic-gate 		if (iocbp->ioc_error) {
61980Sstevel@tonic-gate 			error = iocbp->ioc_error;
61990Sstevel@tonic-gate 			break;
62000Sstevel@tonic-gate 		}
62010Sstevel@tonic-gate 
62020Sstevel@tonic-gate 		/*
62030Sstevel@tonic-gate 		 * Set return value.
62040Sstevel@tonic-gate 		 */
62050Sstevel@tonic-gate 		*rvalp = iocbp->ioc_rval;
62060Sstevel@tonic-gate 
62070Sstevel@tonic-gate 		/*
62080Sstevel@tonic-gate 		 * Data may have been returned in ACK message (ioc_count > 0).
62090Sstevel@tonic-gate 		 * If so, copy it out to the user's buffer.
62100Sstevel@tonic-gate 		 */
62110Sstevel@tonic-gate 		if (iocbp->ioc_count && !transparent) {
62120Sstevel@tonic-gate 			if (error = getiocd(bp, strioc->ic_dp, copyflag))
62130Sstevel@tonic-gate 				break;
62140Sstevel@tonic-gate 		}
62150Sstevel@tonic-gate 		if (!transparent) {
62160Sstevel@tonic-gate 			if (len)	/* an M_COPYOUT was used with I_STR */
62170Sstevel@tonic-gate 				strioc->ic_len = len;
62180Sstevel@tonic-gate 			else
62190Sstevel@tonic-gate 				strioc->ic_len = (int)iocbp->ioc_count;
62200Sstevel@tonic-gate 		}
62210Sstevel@tonic-gate 		break;
62220Sstevel@tonic-gate 
62230Sstevel@tonic-gate 	case M_IOCNAK:
62240Sstevel@tonic-gate 		/*
62250Sstevel@tonic-gate 		 * Negative ack.
62260Sstevel@tonic-gate 		 *
62270Sstevel@tonic-gate 		 * The only thing to do is set error as specified
62280Sstevel@tonic-gate 		 * in neg ack packet.
62290Sstevel@tonic-gate 		 */
62300Sstevel@tonic-gate 		iocbp = (struct iocblk *)bp->b_rptr;
62310Sstevel@tonic-gate 
62320Sstevel@tonic-gate 		error = (iocbp->ioc_error ? iocbp->ioc_error : EINVAL);
62330Sstevel@tonic-gate 		break;
62340Sstevel@tonic-gate 
62350Sstevel@tonic-gate 	case M_COPYIN:
62360Sstevel@tonic-gate 		/*
62370Sstevel@tonic-gate 		 * Driver or module has requested user ioctl data.
62380Sstevel@tonic-gate 		 */
62390Sstevel@tonic-gate 		reqp = (struct copyreq *)bp->b_rptr;
62400Sstevel@tonic-gate 
62410Sstevel@tonic-gate 		/*
62420Sstevel@tonic-gate 		 * M_COPYIN should *never* have a message attached, though
62430Sstevel@tonic-gate 		 * it's harmless if it does -- thus, panic on a DEBUG
62440Sstevel@tonic-gate 		 * kernel and just free it on a non-DEBUG build.
62450Sstevel@tonic-gate 		 */
62460Sstevel@tonic-gate 		ASSERT(bp->b_cont == NULL);
62470Sstevel@tonic-gate 		if (bp->b_cont != NULL) {
62480Sstevel@tonic-gate 			freemsg(bp->b_cont);
62490Sstevel@tonic-gate 			bp->b_cont = NULL;
62500Sstevel@tonic-gate 		}
62510Sstevel@tonic-gate 
62520Sstevel@tonic-gate 		error = putiocd(bp, reqp->cq_addr, flag, crp);
62530Sstevel@tonic-gate 		if (error && bp->b_cont) {
62540Sstevel@tonic-gate 			freemsg(bp->b_cont);
62550Sstevel@tonic-gate 			bp->b_cont = NULL;
62560Sstevel@tonic-gate 		}
62570Sstevel@tonic-gate 
62580Sstevel@tonic-gate 		bp->b_wptr = bp->b_rptr + sizeof (struct copyresp);
62590Sstevel@tonic-gate 		bp->b_datap->db_type = M_IOCDATA;
62600Sstevel@tonic-gate 
62618778SErik.Nordmark@Sun.COM 		mblk_setcred(bp, crp, curproc->p_pid);
62620Sstevel@tonic-gate 		resp = (struct copyresp *)bp->b_rptr;
62630Sstevel@tonic-gate 		resp->cp_rval = (caddr_t)(uintptr_t)error;
62640Sstevel@tonic-gate 		resp->cp_flag = (fflags & FMODELS);
62650Sstevel@tonic-gate 
62660Sstevel@tonic-gate 		stream_willservice(stp);
62670Sstevel@tonic-gate 		putnext(stp->sd_wrq, bp);
62680Sstevel@tonic-gate 		stream_runservice(stp);
62690Sstevel@tonic-gate 
62700Sstevel@tonic-gate 		if (error) {
62710Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
62720Sstevel@tonic-gate 			stp->sd_flag &= ~waitflags;
62730Sstevel@tonic-gate 			cv_broadcast(&stp->sd_iocmonitor);
62740Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
62750Sstevel@tonic-gate 			crfree(crp);
62760Sstevel@tonic-gate 			return (error);
62770Sstevel@tonic-gate 		}
62780Sstevel@tonic-gate 
62790Sstevel@tonic-gate 		goto waitioc;
62800Sstevel@tonic-gate 
62810Sstevel@tonic-gate 	case M_COPYOUT:
62820Sstevel@tonic-gate 		/*
62830Sstevel@tonic-gate 		 * Driver or module has ioctl data for a user.
62840Sstevel@tonic-gate 		 */
62850Sstevel@tonic-gate 		reqp = (struct copyreq *)bp->b_rptr;
62860Sstevel@tonic-gate 		ASSERT(bp->b_cont != NULL);
62870Sstevel@tonic-gate 
62880Sstevel@tonic-gate 		/*
62890Sstevel@tonic-gate 		 * Always (transparent or non-transparent )
62900Sstevel@tonic-gate 		 * use the address specified in the request
62910Sstevel@tonic-gate 		 */
62920Sstevel@tonic-gate 		taddr = reqp->cq_addr;
62930Sstevel@tonic-gate 		if (!transparent)
62940Sstevel@tonic-gate 			len = (int)reqp->cq_size;
62950Sstevel@tonic-gate 
62960Sstevel@tonic-gate 		/* copyout data to the provided address */
62970Sstevel@tonic-gate 		error = getiocd(bp, taddr, copyflag);
62980Sstevel@tonic-gate 
62990Sstevel@tonic-gate 		freemsg(bp->b_cont);
63000Sstevel@tonic-gate 		bp->b_cont = NULL;
63010Sstevel@tonic-gate 
63020Sstevel@tonic-gate 		bp->b_wptr = bp->b_rptr + sizeof (struct copyresp);
63030Sstevel@tonic-gate 		bp->b_datap->db_type = M_IOCDATA;
63040Sstevel@tonic-gate 
63058778SErik.Nordmark@Sun.COM 		mblk_setcred(bp, crp, curproc->p_pid);
63060Sstevel@tonic-gate 		resp = (struct copyresp *)bp->b_rptr;
63070Sstevel@tonic-gate 		resp->cp_rval = (caddr_t)(uintptr_t)error;
63080Sstevel@tonic-gate 		resp->cp_flag = (fflags & FMODELS);
63090Sstevel@tonic-gate 
63100Sstevel@tonic-gate 		stream_willservice(stp);
63110Sstevel@tonic-gate 		putnext(stp->sd_wrq, bp);
63120Sstevel@tonic-gate 		stream_runservice(stp);
63130Sstevel@tonic-gate 
63140Sstevel@tonic-gate 		if (error) {
63150Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
63160Sstevel@tonic-gate 			stp->sd_flag &= ~waitflags;
63170Sstevel@tonic-gate 			cv_broadcast(&stp->sd_iocmonitor);
63180Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
63190Sstevel@tonic-gate 			crfree(crp);
63200Sstevel@tonic-gate 			return (error);
63210Sstevel@tonic-gate 		}
63220Sstevel@tonic-gate 		goto waitioc;
63230Sstevel@tonic-gate 
63240Sstevel@tonic-gate 	default:
63250Sstevel@tonic-gate 		ASSERT(0);
63260Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
63270Sstevel@tonic-gate 		stp->sd_flag &= ~waitflags;
63280Sstevel@tonic-gate 		cv_broadcast(&stp->sd_iocmonitor);
63290Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
63300Sstevel@tonic-gate 		break;
63310Sstevel@tonic-gate 	}
63320Sstevel@tonic-gate 
63330Sstevel@tonic-gate 	freemsg(bp);
63340Sstevel@tonic-gate 	crfree(crp);
63350Sstevel@tonic-gate 	return (error);
63360Sstevel@tonic-gate }
63370Sstevel@tonic-gate 
63380Sstevel@tonic-gate /*
63396583Smeem  * Send an M_CMD message downstream and wait for a reply.  This is a ptools
63406583Smeem  * special used to retrieve information from modules/drivers a stream without
63416583Smeem  * being subjected to flow control or interfering with pending messages on the
63426583Smeem  * stream (e.g. an ioctl in flight).
63436583Smeem  */
63446583Smeem int
strdocmd(struct stdata * stp,struct strcmd * scp,cred_t * crp)63456583Smeem strdocmd(struct stdata *stp, struct strcmd *scp, cred_t *crp)
63466583Smeem {
63476583Smeem 	mblk_t *mp;
63486583Smeem 	struct cmdblk *cmdp;
63496583Smeem 	int error = 0;
63506583Smeem 	int errs = STRHUP|STRDERR|STWRERR|STPLEX;
63516583Smeem 	clock_t rval, timeout = STRTIMOUT;
63526583Smeem 
63536583Smeem 	if (scp->sc_len < 0 || scp->sc_len > sizeof (scp->sc_buf) ||
63546583Smeem 	    scp->sc_timeout < -1)
63556583Smeem 		return (EINVAL);
63566583Smeem 
63576583Smeem 	if (scp->sc_timeout > 0)
63586583Smeem 		timeout = scp->sc_timeout * MILLISEC;
63596583Smeem 
63608778SErik.Nordmark@Sun.COM 	if ((mp = allocb_cred(sizeof (struct cmdblk), crp,
63618778SErik.Nordmark@Sun.COM 	    curproc->p_pid)) == NULL)
63626583Smeem 		return (ENOMEM);
63636583Smeem 
63646583Smeem 	crhold(crp);
63656583Smeem 
63666583Smeem 	cmdp = (struct cmdblk *)mp->b_wptr;
63676583Smeem 	cmdp->cb_cr = crp;
63686583Smeem 	cmdp->cb_cmd = scp->sc_cmd;
63696583Smeem 	cmdp->cb_len = scp->sc_len;
63706583Smeem 	cmdp->cb_error = 0;
63716583Smeem 	mp->b_wptr += sizeof (struct cmdblk);
63726583Smeem 
63736583Smeem 	DB_TYPE(mp) = M_CMD;
63746583Smeem 	DB_CPID(mp) = curproc->p_pid;
63756583Smeem 
63766583Smeem 	/*
63776583Smeem 	 * Copy in the payload.
63786583Smeem 	 */
63796583Smeem 	if (cmdp->cb_len > 0) {
63808778SErik.Nordmark@Sun.COM 		mp->b_cont = allocb_cred(sizeof (scp->sc_buf), crp,
63818778SErik.Nordmark@Sun.COM 		    curproc->p_pid);
63826583Smeem 		if (mp->b_cont == NULL) {
63836583Smeem 			error = ENOMEM;
63846583Smeem 			goto out;
63856583Smeem 		}
63866583Smeem 
63876583Smeem 		/* cb_len comes from sc_len, which has already been checked */
63886583Smeem 		ASSERT(cmdp->cb_len <= sizeof (scp->sc_buf));
63896583Smeem 		(void) bcopy(scp->sc_buf, mp->b_cont->b_wptr, cmdp->cb_len);
63906583Smeem 		mp->b_cont->b_wptr += cmdp->cb_len;
63916583Smeem 		DB_CPID(mp->b_cont) = curproc->p_pid;
63926583Smeem 	}
63936583Smeem 
63946583Smeem 	/*
63956583Smeem 	 * Since this mechanism is strictly for ptools, and since only one
63966583Smeem 	 * process can be grabbed at a time, we simply fail if there's
63976583Smeem 	 * currently an operation pending.
63986583Smeem 	 */
63996583Smeem 	mutex_enter(&stp->sd_lock);
64006583Smeem 	if (stp->sd_flag & STRCMDWAIT) {
64016583Smeem 		mutex_exit(&stp->sd_lock);
64026583Smeem 		error = EBUSY;
64036583Smeem 		goto out;
64046583Smeem 	}
64056583Smeem 	stp->sd_flag |= STRCMDWAIT;
64066583Smeem 	ASSERT(stp->sd_cmdblk == NULL);
64076583Smeem 	mutex_exit(&stp->sd_lock);
64086583Smeem 
64096583Smeem 	putnext(stp->sd_wrq, mp);
64106583Smeem 	mp = NULL;
64116583Smeem 
64126583Smeem 	/*
64136583Smeem 	 * Timed wait for acknowledgment.  If the reply has already arrived,
64146583Smeem 	 * don't sleep.  If awakened from the sleep, fail only if the reply
64156583Smeem 	 * has not arrived by then.  Otherwise, process the reply.
64166583Smeem 	 */
64176583Smeem 	mutex_enter(&stp->sd_lock);
64186583Smeem 	while (stp->sd_cmdblk == NULL) {
64196583Smeem 		if (stp->sd_flag & errs) {
64206583Smeem 			if ((error = strgeterr(stp, errs, 0)) != 0)
64216583Smeem 				goto waitout;
64226583Smeem 		}
64236583Smeem 
64246583Smeem 		rval = str_cv_wait(&stp->sd_monitor, &stp->sd_lock, timeout, 0);
64256583Smeem 		if (stp->sd_cmdblk != NULL)
64266583Smeem 			break;
64276583Smeem 
64286583Smeem 		if (rval <= 0) {
64296583Smeem 			error = (rval == 0) ? EINTR : ETIME;
64306583Smeem 			goto waitout;
64316583Smeem 		}
64326583Smeem 	}
64336583Smeem 
64346583Smeem 	/*
64356583Smeem 	 * We received a reply.
64366583Smeem 	 */
64376583Smeem 	mp = stp->sd_cmdblk;
64386583Smeem 	stp->sd_cmdblk = NULL;
64396583Smeem 	ASSERT(mp != NULL && DB_TYPE(mp) == M_CMD);
64406583Smeem 	ASSERT(stp->sd_flag & STRCMDWAIT);
64416583Smeem 	stp->sd_flag &= ~STRCMDWAIT;
64426583Smeem 	mutex_exit(&stp->sd_lock);
64436583Smeem 
64446583Smeem 	cmdp = (struct cmdblk *)mp->b_rptr;
64456583Smeem 	if ((error = cmdp->cb_error) != 0)
64466583Smeem 		goto out;
64476583Smeem 
64486583Smeem 	/*
64496583Smeem 	 * Data may have been returned in the reply (cb_len > 0).
64506583Smeem 	 * If so, copy it out to the user's buffer.
64516583Smeem 	 */
64526583Smeem 	if (cmdp->cb_len > 0) {
64536583Smeem 		if (mp->b_cont == NULL || MBLKL(mp->b_cont) < cmdp->cb_len) {
64546583Smeem 			error = EPROTO;
64556583Smeem 			goto out;
64566583Smeem 		}
64576583Smeem 
64586583Smeem 		cmdp->cb_len = MIN(cmdp->cb_len, sizeof (scp->sc_buf));
64596583Smeem 		(void) bcopy(mp->b_cont->b_rptr, scp->sc_buf, cmdp->cb_len);
64606583Smeem 	}
64616583Smeem 	scp->sc_len = cmdp->cb_len;
64626583Smeem out:
64636583Smeem 	freemsg(mp);
64646583Smeem 	crfree(crp);
64656583Smeem 	return (error);
64666583Smeem waitout:
64676583Smeem 	ASSERT(stp->sd_cmdblk == NULL);
64686583Smeem 	stp->sd_flag &= ~STRCMDWAIT;
64696583Smeem 	mutex_exit(&stp->sd_lock);
64706583Smeem 	crfree(crp);
64716583Smeem 	return (error);
64726583Smeem }
64736583Smeem 
64746583Smeem /*
64750Sstevel@tonic-gate  * For the SunOS keyboard driver.
64760Sstevel@tonic-gate  * Return the next available "ioctl" sequence number.
64770Sstevel@tonic-gate  * Exported, so that streams modules can send "ioctl" messages
64780Sstevel@tonic-gate  * downstream from their open routine.
64790Sstevel@tonic-gate  */
64800Sstevel@tonic-gate int
getiocseqno(void)64810Sstevel@tonic-gate getiocseqno(void)
64820Sstevel@tonic-gate {
64830Sstevel@tonic-gate 	int	i;
64840Sstevel@tonic-gate 
64850Sstevel@tonic-gate 	mutex_enter(&strresources);
64860Sstevel@tonic-gate 	i = ++ioc_id;
64870Sstevel@tonic-gate 	mutex_exit(&strresources);
64880Sstevel@tonic-gate 	return (i);
64890Sstevel@tonic-gate }
64900Sstevel@tonic-gate 
64910Sstevel@tonic-gate /*
64920Sstevel@tonic-gate  * Get the next message from the read queue.  If the message is
64930Sstevel@tonic-gate  * priority, STRPRI will have been set by strrput().  This flag
64940Sstevel@tonic-gate  * should be reset only when the entire message at the front of the
64950Sstevel@tonic-gate  * queue as been consumed.
64960Sstevel@tonic-gate  *
64970Sstevel@tonic-gate  * NOTE: strgetmsg and kstrgetmsg have much of the logic in common.
64980Sstevel@tonic-gate  */
64990Sstevel@tonic-gate int
strgetmsg(struct vnode * vp,struct strbuf * mctl,struct strbuf * mdata,unsigned char * prip,int * flagsp,int fmode,rval_t * rvp)65000Sstevel@tonic-gate strgetmsg(
65010Sstevel@tonic-gate 	struct vnode *vp,
65020Sstevel@tonic-gate 	struct strbuf *mctl,
65030Sstevel@tonic-gate 	struct strbuf *mdata,
65040Sstevel@tonic-gate 	unsigned char *prip,
65050Sstevel@tonic-gate 	int *flagsp,
65060Sstevel@tonic-gate 	int fmode,
65070Sstevel@tonic-gate 	rval_t *rvp)
65080Sstevel@tonic-gate {
65090Sstevel@tonic-gate 	struct stdata *stp;
65100Sstevel@tonic-gate 	mblk_t *bp, *nbp;
65110Sstevel@tonic-gate 	mblk_t *savemp = NULL;
65120Sstevel@tonic-gate 	mblk_t *savemptail = NULL;
65130Sstevel@tonic-gate 	uint_t old_sd_flag;
65140Sstevel@tonic-gate 	int flg;
65150Sstevel@tonic-gate 	int more = 0;
65160Sstevel@tonic-gate 	int error = 0;
65170Sstevel@tonic-gate 	char first = 1;
65180Sstevel@tonic-gate 	uint_t mark;		/* Contains MSG*MARK and _LASTMARK */
65190Sstevel@tonic-gate #define	_LASTMARK	0x8000	/* Distinct from MSG*MARK */
65200Sstevel@tonic-gate 	unsigned char pri = 0;
65210Sstevel@tonic-gate 	queue_t *q;
65220Sstevel@tonic-gate 	int	pr = 0;			/* Partial read successful */
65230Sstevel@tonic-gate 	struct uio uios;
65240Sstevel@tonic-gate 	struct uio *uiop = &uios;
65250Sstevel@tonic-gate 	struct iovec iovs;
65260Sstevel@tonic-gate 	unsigned char type;
65270Sstevel@tonic-gate 
65280Sstevel@tonic-gate 	TRACE_1(TR_FAC_STREAMS_FR, TR_STRGETMSG_ENTER,
65295753Sgww 	    "strgetmsg:%p", vp);
65300Sstevel@tonic-gate 
65310Sstevel@tonic-gate 	ASSERT(vp->v_stream);
65320Sstevel@tonic-gate 	stp = vp->v_stream;
65330Sstevel@tonic-gate 	rvp->r_val1 = 0;
65340Sstevel@tonic-gate 
65352712Snn35248 	mutex_enter(&stp->sd_lock);
65362712Snn35248 
65372712Snn35248 	if ((error = i_straccess(stp, JCREAD)) != 0) {
65382712Snn35248 		mutex_exit(&stp->sd_lock);
65392712Snn35248 		return (error);
65402712Snn35248 	}
65412712Snn35248 
65420Sstevel@tonic-gate 	if (stp->sd_flag & (STRDERR|STPLEX)) {
65430Sstevel@tonic-gate 		error = strgeterr(stp, STRDERR|STPLEX, 0);
65442712Snn35248 		if (error != 0) {
65452712Snn35248 			mutex_exit(&stp->sd_lock);
65460Sstevel@tonic-gate 			return (error);
65472712Snn35248 		}
65482712Snn35248 	}
65492712Snn35248 	mutex_exit(&stp->sd_lock);
65500Sstevel@tonic-gate 
65510Sstevel@tonic-gate 	switch (*flagsp) {
65520Sstevel@tonic-gate 	case MSG_HIPRI:
65530Sstevel@tonic-gate 		if (*prip != 0)
65540Sstevel@tonic-gate 			return (EINVAL);
65550Sstevel@tonic-gate 		break;
65560Sstevel@tonic-gate 
65570Sstevel@tonic-gate 	case MSG_ANY:
65580Sstevel@tonic-gate 	case MSG_BAND:
65590Sstevel@tonic-gate 		break;
65600Sstevel@tonic-gate 
65610Sstevel@tonic-gate 	default:
65620Sstevel@tonic-gate 		return (EINVAL);
65630Sstevel@tonic-gate 	}
65640Sstevel@tonic-gate 	/*
65650Sstevel@tonic-gate 	 * Setup uio and iov for data part
65660Sstevel@tonic-gate 	 */
65670Sstevel@tonic-gate 	iovs.iov_base = mdata->buf;
65680Sstevel@tonic-gate 	iovs.iov_len = mdata->maxlen;
65690Sstevel@tonic-gate 	uios.uio_iov = &iovs;
65700Sstevel@tonic-gate 	uios.uio_iovcnt = 1;
65710Sstevel@tonic-gate 	uios.uio_loffset = 0;
65720Sstevel@tonic-gate 	uios.uio_segflg = UIO_USERSPACE;
65730Sstevel@tonic-gate 	uios.uio_fmode = 0;
65740Sstevel@tonic-gate 	uios.uio_extflg = UIO_COPY_CACHED;
65750Sstevel@tonic-gate 	uios.uio_resid = mdata->maxlen;
65760Sstevel@tonic-gate 	uios.uio_offset = 0;
65770Sstevel@tonic-gate 
65780Sstevel@tonic-gate 	q = _RD(stp->sd_wrq);
65790Sstevel@tonic-gate 	mutex_enter(&stp->sd_lock);
65800Sstevel@tonic-gate 	old_sd_flag = stp->sd_flag;
65810Sstevel@tonic-gate 	mark = 0;
65820Sstevel@tonic-gate 	for (;;) {
65830Sstevel@tonic-gate 		int done = 0;
65840Sstevel@tonic-gate 		mblk_t *q_first = q->q_first;
65850Sstevel@tonic-gate 
65860Sstevel@tonic-gate 		/*
65870Sstevel@tonic-gate 		 * Get the next message of appropriate priority
65880Sstevel@tonic-gate 		 * from the stream head.  If the caller is interested
65890Sstevel@tonic-gate 		 * in band or hipri messages, then they should already
65900Sstevel@tonic-gate 		 * be enqueued at the stream head.  On the other hand
65910Sstevel@tonic-gate 		 * if the caller wants normal (band 0) messages, they
65920Sstevel@tonic-gate 		 * might be deferred in a synchronous stream and they
65930Sstevel@tonic-gate 		 * will need to be pulled up.
65940Sstevel@tonic-gate 		 *
65950Sstevel@tonic-gate 		 * After we have dequeued a message, we might find that
65960Sstevel@tonic-gate 		 * it was a deferred M_SIG that was enqueued at the
65970Sstevel@tonic-gate 		 * stream head.  It must now be posted as part of the
65980Sstevel@tonic-gate 		 * read by calling strsignal_nolock().
65990Sstevel@tonic-gate 		 *
66000Sstevel@tonic-gate 		 * Also note that strrput does not enqueue an M_PCSIG,
66010Sstevel@tonic-gate 		 * and there cannot be more than one hipri message,
66020Sstevel@tonic-gate 		 * so there was no need to have the M_PCSIG case.
66030Sstevel@tonic-gate 		 *
66040Sstevel@tonic-gate 		 * At some time it might be nice to try and wrap the
66050Sstevel@tonic-gate 		 * functionality of kstrgetmsg() and strgetmsg() into
66060Sstevel@tonic-gate 		 * a common routine so to reduce the amount of replicated
66070Sstevel@tonic-gate 		 * code (since they are extremely similar).
66080Sstevel@tonic-gate 		 */
66090Sstevel@tonic-gate 		if (!(*flagsp & (MSG_HIPRI|MSG_BAND))) {
66100Sstevel@tonic-gate 			/* Asking for normal, band0 data */
66110Sstevel@tonic-gate 			bp = strget(stp, q, uiop, first, &error);
66120Sstevel@tonic-gate 			ASSERT(MUTEX_HELD(&stp->sd_lock));
66130Sstevel@tonic-gate 			if (bp != NULL) {
66148752SPeter.Memishian@Sun.COM 				if (DB_TYPE(bp) == M_SIG) {
66150Sstevel@tonic-gate 					strsignal_nolock(stp, *bp->b_rptr,
66168752SPeter.Memishian@Sun.COM 					    bp->b_band);
66178752SPeter.Memishian@Sun.COM 					freemsg(bp);
66180Sstevel@tonic-gate 					continue;
66190Sstevel@tonic-gate 				} else {
66200Sstevel@tonic-gate 					break;
66210Sstevel@tonic-gate 				}
66220Sstevel@tonic-gate 			}
66238752SPeter.Memishian@Sun.COM 			if (error != 0)
66240Sstevel@tonic-gate 				goto getmout;
66250Sstevel@tonic-gate 
66260Sstevel@tonic-gate 		/*
66270Sstevel@tonic-gate 		 * We can't depend on the value of STRPRI here because
66280Sstevel@tonic-gate 		 * the stream head may be in transit. Therefore, we
66290Sstevel@tonic-gate 		 * must look at the type of the first message to
66300Sstevel@tonic-gate 		 * determine if a high priority messages is waiting
66310Sstevel@tonic-gate 		 */
66320Sstevel@tonic-gate 		} else if ((*flagsp & MSG_HIPRI) && q_first != NULL &&
66338752SPeter.Memishian@Sun.COM 		    DB_TYPE(q_first) >= QPCTL &&
66346769Sja97890 		    (bp = getq_noenab(q, 0)) != NULL) {
66350Sstevel@tonic-gate 			/* Asked for HIPRI and got one */
66368752SPeter.Memishian@Sun.COM 			ASSERT(DB_TYPE(bp) >= QPCTL);
66370Sstevel@tonic-gate 			break;
66380Sstevel@tonic-gate 		} else if ((*flagsp & MSG_BAND) && q_first != NULL &&
66398752SPeter.Memishian@Sun.COM 		    ((q_first->b_band >= *prip) || DB_TYPE(q_first) >= QPCTL) &&
66406769Sja97890 		    (bp = getq_noenab(q, 0)) != NULL) {
66410Sstevel@tonic-gate 			/*
66420Sstevel@tonic-gate 			 * Asked for at least band "prip" and got either at
66430Sstevel@tonic-gate 			 * least that band or a hipri message.
66440Sstevel@tonic-gate 			 */
66458752SPeter.Memishian@Sun.COM 			ASSERT(bp->b_band >= *prip || DB_TYPE(bp) >= QPCTL);
66468752SPeter.Memishian@Sun.COM 			if (DB_TYPE(bp) == M_SIG) {
66478752SPeter.Memishian@Sun.COM 				strsignal_nolock(stp, *bp->b_rptr, bp->b_band);
66488752SPeter.Memishian@Sun.COM 				freemsg(bp);
66490Sstevel@tonic-gate 				continue;
66500Sstevel@tonic-gate 			} else {
66510Sstevel@tonic-gate 				break;
66520Sstevel@tonic-gate 			}
66530Sstevel@tonic-gate 		}
66540Sstevel@tonic-gate 
66550Sstevel@tonic-gate 		/* No data. Time to sleep? */
66560Sstevel@tonic-gate 		qbackenable(q, 0);
66570Sstevel@tonic-gate 
66580Sstevel@tonic-gate 		/*
66590Sstevel@tonic-gate 		 * If STRHUP or STREOF, return 0 length control and data.
66600Sstevel@tonic-gate 		 * If resid is 0, then a read(fd,buf,0) was done. Do not
66610Sstevel@tonic-gate 		 * sleep to satisfy this request because by default we have
66620Sstevel@tonic-gate 		 * zero bytes to return.
66630Sstevel@tonic-gate 		 */
66640Sstevel@tonic-gate 		if ((stp->sd_flag & (STRHUP|STREOF)) || (mctl->maxlen == 0 &&
66650Sstevel@tonic-gate 		    mdata->maxlen == 0)) {
66660Sstevel@tonic-gate 			mctl->len = mdata->len = 0;
66670Sstevel@tonic-gate 			*flagsp = 0;
66680Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
66690Sstevel@tonic-gate 			return (0);
66700Sstevel@tonic-gate 		}
66710Sstevel@tonic-gate 		TRACE_2(TR_FAC_STREAMS_FR, TR_STRGETMSG_WAIT,
66725753Sgww 		    "strgetmsg calls strwaitq:%p, %p",
66735753Sgww 		    vp, uiop);
66740Sstevel@tonic-gate 		if (((error = strwaitq(stp, GETWAIT, (ssize_t)0, fmode, -1,
66750Sstevel@tonic-gate 		    &done)) != 0) || done) {
66760Sstevel@tonic-gate 			TRACE_2(TR_FAC_STREAMS_FR, TR_STRGETMSG_DONE,
66775753Sgww 			    "strgetmsg error or done:%p, %p",
66785753Sgww 			    vp, uiop);
66790Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
66800Sstevel@tonic-gate 			return (error);
66810Sstevel@tonic-gate 		}
66820Sstevel@tonic-gate 		TRACE_2(TR_FAC_STREAMS_FR, TR_STRGETMSG_AWAKE,
66835753Sgww 		    "strgetmsg awakes:%p, %p", vp, uiop);
66842712Snn35248 		if ((error = i_straccess(stp, JCREAD)) != 0) {
66850Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
66862712Snn35248 			return (error);
66870Sstevel@tonic-gate 		}
66880Sstevel@tonic-gate 		first = 0;
66890Sstevel@tonic-gate 	}
66900Sstevel@tonic-gate 	ASSERT(bp != NULL);
66910Sstevel@tonic-gate 	/*
66920Sstevel@tonic-gate 	 * Extract any mark information. If the message is not completely
66930Sstevel@tonic-gate 	 * consumed this information will be put in the mblk
66940Sstevel@tonic-gate 	 * that is putback.
66950Sstevel@tonic-gate 	 * If MSGMARKNEXT is set and the message is completely consumed
66960Sstevel@tonic-gate 	 * the STRATMARK flag will be set below. Likewise, if
66970Sstevel@tonic-gate 	 * MSGNOTMARKNEXT is set and the message is
66980Sstevel@tonic-gate 	 * completely consumed STRNOTATMARK will be set.
66990Sstevel@tonic-gate 	 */
67000Sstevel@tonic-gate 	mark = bp->b_flag & (MSGMARK | MSGMARKNEXT | MSGNOTMARKNEXT);
67010Sstevel@tonic-gate 	ASSERT((mark & (MSGMARKNEXT|MSGNOTMARKNEXT)) !=
67025753Sgww 	    (MSGMARKNEXT|MSGNOTMARKNEXT));
67030Sstevel@tonic-gate 	if (mark != 0 && bp == stp->sd_mark) {
67040Sstevel@tonic-gate 		mark |= _LASTMARK;
67050Sstevel@tonic-gate 		stp->sd_mark = NULL;
67060Sstevel@tonic-gate 	}
67070Sstevel@tonic-gate 	/*
67080Sstevel@tonic-gate 	 * keep track of the original message type and priority
67090Sstevel@tonic-gate 	 */
67100Sstevel@tonic-gate 	pri = bp->b_band;
67110Sstevel@tonic-gate 	type = bp->b_datap->db_type;
67120Sstevel@tonic-gate 	if (type == M_PASSFP) {
67130Sstevel@tonic-gate 		if ((mark & _LASTMARK) && (stp->sd_mark == NULL))
67140Sstevel@tonic-gate 			stp->sd_mark = bp;
67150Sstevel@tonic-gate 		bp->b_flag |= mark & ~_LASTMARK;
67160Sstevel@tonic-gate 		putback(stp, q, bp, pri);
67170Sstevel@tonic-gate 		qbackenable(q, pri);
67180Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
67190Sstevel@tonic-gate 		return (EBADMSG);
67200Sstevel@tonic-gate 	}
67210Sstevel@tonic-gate 	ASSERT(type != M_SIG);
67220Sstevel@tonic-gate 
67230Sstevel@tonic-gate 	/*
67240Sstevel@tonic-gate 	 * Set this flag so strrput will not generate signals. Need to
67250Sstevel@tonic-gate 	 * make sure this flag is cleared before leaving this routine
67260Sstevel@tonic-gate 	 * else signals will stop being sent.
67270Sstevel@tonic-gate 	 */
67280Sstevel@tonic-gate 	stp->sd_flag |= STRGETINPROG;
67290Sstevel@tonic-gate 	mutex_exit(&stp->sd_lock);
67300Sstevel@tonic-gate 
67310Sstevel@tonic-gate 	if (STREAM_NEEDSERVICE(stp))
67320Sstevel@tonic-gate 		stream_runservice(stp);
67330Sstevel@tonic-gate 
67340Sstevel@tonic-gate 	/*
67350Sstevel@tonic-gate 	 * Set HIPRI flag if message is priority.
67360Sstevel@tonic-gate 	 */
67370Sstevel@tonic-gate 	if (type >= QPCTL)
67380Sstevel@tonic-gate 		flg = MSG_HIPRI;
67390Sstevel@tonic-gate 	else
67400Sstevel@tonic-gate 		flg = MSG_BAND;
67410Sstevel@tonic-gate 
67420Sstevel@tonic-gate 	/*
67430Sstevel@tonic-gate 	 * First process PROTO or PCPROTO blocks, if any.
67440Sstevel@tonic-gate 	 */
67450Sstevel@tonic-gate 	if (mctl->maxlen >= 0 && type != M_DATA) {
67460Sstevel@tonic-gate 		size_t	n, bcnt;
67470Sstevel@tonic-gate 		char	*ubuf;
67480Sstevel@tonic-gate 
67490Sstevel@tonic-gate 		bcnt = mctl->maxlen;
67500Sstevel@tonic-gate 		ubuf = mctl->buf;
67510Sstevel@tonic-gate 		while (bp != NULL && bp->b_datap->db_type != M_DATA) {
67520Sstevel@tonic-gate 			if ((n = MIN(bcnt, bp->b_wptr - bp->b_rptr)) != 0 &&
67530Sstevel@tonic-gate 			    copyout(bp->b_rptr, ubuf, n)) {
67540Sstevel@tonic-gate 				error = EFAULT;
67550Sstevel@tonic-gate 				mutex_enter(&stp->sd_lock);
67560Sstevel@tonic-gate 				/*
67570Sstevel@tonic-gate 				 * clear stream head pri flag based on
67580Sstevel@tonic-gate 				 * first message type
67590Sstevel@tonic-gate 				 */
67600Sstevel@tonic-gate 				if (type >= QPCTL) {
67610Sstevel@tonic-gate 					ASSERT(type == M_PCPROTO);
67620Sstevel@tonic-gate 					stp->sd_flag &= ~STRPRI;
67630Sstevel@tonic-gate 				}
67640Sstevel@tonic-gate 				more = 0;
67650Sstevel@tonic-gate 				freemsg(bp);
67660Sstevel@tonic-gate 				goto getmout;
67670Sstevel@tonic-gate 			}
67680Sstevel@tonic-gate 			ubuf += n;
67690Sstevel@tonic-gate 			bp->b_rptr += n;
67700Sstevel@tonic-gate 			if (bp->b_rptr >= bp->b_wptr) {
67710Sstevel@tonic-gate 				nbp = bp;
67720Sstevel@tonic-gate 				bp = bp->b_cont;
67730Sstevel@tonic-gate 				freeb(nbp);
67740Sstevel@tonic-gate 			}
67750Sstevel@tonic-gate 			ASSERT(n <= bcnt);
67760Sstevel@tonic-gate 			bcnt -= n;
67770Sstevel@tonic-gate 			if (bcnt == 0)
67780Sstevel@tonic-gate 				break;
67790Sstevel@tonic-gate 		}
67800Sstevel@tonic-gate 		mctl->len = mctl->maxlen - bcnt;
67810Sstevel@tonic-gate 	} else
67820Sstevel@tonic-gate 		mctl->len = -1;
67830Sstevel@tonic-gate 
67840Sstevel@tonic-gate 	if (bp && bp->b_datap->db_type != M_DATA) {
67850Sstevel@tonic-gate 		/*
67860Sstevel@tonic-gate 		 * More PROTO blocks in msg.
67870Sstevel@tonic-gate 		 */
67880Sstevel@tonic-gate 		more |= MORECTL;
67890Sstevel@tonic-gate 		savemp = bp;
67900Sstevel@tonic-gate 		while (bp && bp->b_datap->db_type != M_DATA) {
67910Sstevel@tonic-gate 			savemptail = bp;
67920Sstevel@tonic-gate 			bp = bp->b_cont;
67930Sstevel@tonic-gate 		}
67940Sstevel@tonic-gate 		savemptail->b_cont = NULL;
67950Sstevel@tonic-gate 	}
67960Sstevel@tonic-gate 
67970Sstevel@tonic-gate 	/*
67980Sstevel@tonic-gate 	 * Now process DATA blocks, if any.
67990Sstevel@tonic-gate 	 */
68000Sstevel@tonic-gate 	if (mdata->maxlen >= 0 && bp) {
68010Sstevel@tonic-gate 		/*
68020Sstevel@tonic-gate 		 * struiocopyout will consume a potential zero-length
68030Sstevel@tonic-gate 		 * M_DATA even if uio_resid is zero.
68040Sstevel@tonic-gate 		 */
68050Sstevel@tonic-gate 		size_t oldresid = uiop->uio_resid;
68060Sstevel@tonic-gate 
68070Sstevel@tonic-gate 		bp = struiocopyout(bp, uiop, &error);
68080Sstevel@tonic-gate 		if (error != 0) {
68090Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
68100Sstevel@tonic-gate 			/*
68110Sstevel@tonic-gate 			 * clear stream head hi pri flag based on
68120Sstevel@tonic-gate 			 * first message
68130Sstevel@tonic-gate 			 */
68140Sstevel@tonic-gate 			if (type >= QPCTL) {
68150Sstevel@tonic-gate 				ASSERT(type == M_PCPROTO);
68160Sstevel@tonic-gate 				stp->sd_flag &= ~STRPRI;
68170Sstevel@tonic-gate 			}
68180Sstevel@tonic-gate 			more = 0;
68190Sstevel@tonic-gate 			freemsg(savemp);
68200Sstevel@tonic-gate 			goto getmout;
68210Sstevel@tonic-gate 		}
68220Sstevel@tonic-gate 		/*
68230Sstevel@tonic-gate 		 * (pr == 1) indicates a partial read.
68240Sstevel@tonic-gate 		 */
68250Sstevel@tonic-gate 		if (oldresid > uiop->uio_resid)
68260Sstevel@tonic-gate 			pr = 1;
68270Sstevel@tonic-gate 		mdata->len = mdata->maxlen - uiop->uio_resid;
68280Sstevel@tonic-gate 	} else
68290Sstevel@tonic-gate 		mdata->len = -1;
68300Sstevel@tonic-gate 
68310Sstevel@tonic-gate 	if (bp) {			/* more data blocks in msg */
68320Sstevel@tonic-gate 		more |= MOREDATA;
68330Sstevel@tonic-gate 		if (savemp)
68340Sstevel@tonic-gate 			savemptail->b_cont = bp;
68350Sstevel@tonic-gate 		else
68360Sstevel@tonic-gate 			savemp = bp;
68370Sstevel@tonic-gate 	}
68380Sstevel@tonic-gate 
68390Sstevel@tonic-gate 	mutex_enter(&stp->sd_lock);
68400Sstevel@tonic-gate 	if (savemp) {
68410Sstevel@tonic-gate 		if (pr && (savemp->b_datap->db_type == M_DATA) &&
68420Sstevel@tonic-gate 		    msgnodata(savemp)) {
68430Sstevel@tonic-gate 			/*
68440Sstevel@tonic-gate 			 * Avoid queuing a zero-length tail part of
68450Sstevel@tonic-gate 			 * a message. pr=1 indicates that we read some of
68460Sstevel@tonic-gate 			 * the message.
68470Sstevel@tonic-gate 			 */
68480Sstevel@tonic-gate 			freemsg(savemp);
68490Sstevel@tonic-gate 			more &= ~MOREDATA;
68500Sstevel@tonic-gate 			/*
68510Sstevel@tonic-gate 			 * clear stream head hi pri flag based on
68520Sstevel@tonic-gate 			 * first message
68530Sstevel@tonic-gate 			 */
68540Sstevel@tonic-gate 			if (type >= QPCTL) {
68550Sstevel@tonic-gate 				ASSERT(type == M_PCPROTO);
68560Sstevel@tonic-gate 				stp->sd_flag &= ~STRPRI;
68570Sstevel@tonic-gate 			}
68580Sstevel@tonic-gate 		} else {
68590Sstevel@tonic-gate 			savemp->b_band = pri;
68600Sstevel@tonic-gate 			/*
68610Sstevel@tonic-gate 			 * If the first message was HIPRI and the one we're
68620Sstevel@tonic-gate 			 * putting back isn't, then clear STRPRI, otherwise
68630Sstevel@tonic-gate 			 * set STRPRI again.  Note that we must set STRPRI
68640Sstevel@tonic-gate 			 * again since the flush logic in strrput_nondata()
68650Sstevel@tonic-gate 			 * may have cleared it while we had sd_lock dropped.
68660Sstevel@tonic-gate 			 */
68670Sstevel@tonic-gate 			if (type >= QPCTL) {
68680Sstevel@tonic-gate 				ASSERT(type == M_PCPROTO);
68690Sstevel@tonic-gate 				if (queclass(savemp) < QPCTL)
68700Sstevel@tonic-gate 					stp->sd_flag &= ~STRPRI;
68710Sstevel@tonic-gate 				else
68720Sstevel@tonic-gate 					stp->sd_flag |= STRPRI;
68730Sstevel@tonic-gate 			} else if (queclass(savemp) >= QPCTL) {
68740Sstevel@tonic-gate 				/*
68750Sstevel@tonic-gate 				 * The first message was not a HIPRI message,
68760Sstevel@tonic-gate 				 * but the one we are about to putback is.
68770Sstevel@tonic-gate 				 * For simplicitly, we do not allow for HIPRI
68780Sstevel@tonic-gate 				 * messages to be embedded in the message
68790Sstevel@tonic-gate 				 * body, so just force it to same type as
68800Sstevel@tonic-gate 				 * first message.
68810Sstevel@tonic-gate 				 */
68820Sstevel@tonic-gate 				ASSERT(type == M_DATA || type == M_PROTO);
68830Sstevel@tonic-gate 				ASSERT(savemp->b_datap->db_type == M_PCPROTO);
68840Sstevel@tonic-gate 				savemp->b_datap->db_type = type;
68850Sstevel@tonic-gate 			}
68860Sstevel@tonic-gate 			if (mark != 0) {
68870Sstevel@tonic-gate 				savemp->b_flag |= mark & ~_LASTMARK;
68880Sstevel@tonic-gate 				if ((mark & _LASTMARK) &&
68890Sstevel@tonic-gate 				    (stp->sd_mark == NULL)) {
68900Sstevel@tonic-gate 					/*
68910Sstevel@tonic-gate 					 * If another marked message arrived
68920Sstevel@tonic-gate 					 * while sd_lock was not held sd_mark
68930Sstevel@tonic-gate 					 * would be non-NULL.
68940Sstevel@tonic-gate 					 */
68950Sstevel@tonic-gate 					stp->sd_mark = savemp;
68960Sstevel@tonic-gate 				}
68970Sstevel@tonic-gate 			}
68980Sstevel@tonic-gate 			putback(stp, q, savemp, pri);
68990Sstevel@tonic-gate 		}
69000Sstevel@tonic-gate 	} else {
69010Sstevel@tonic-gate 		/*
69020Sstevel@tonic-gate 		 * The complete message was consumed.
69030Sstevel@tonic-gate 		 *
69040Sstevel@tonic-gate 		 * If another M_PCPROTO arrived while sd_lock was not held
69050Sstevel@tonic-gate 		 * it would have been discarded since STRPRI was still set.
69060Sstevel@tonic-gate 		 *
69070Sstevel@tonic-gate 		 * Move the MSG*MARKNEXT information
69080Sstevel@tonic-gate 		 * to the stream head just in case
69090Sstevel@tonic-gate 		 * the read queue becomes empty.
69100Sstevel@tonic-gate 		 * clear stream head hi pri flag based on
69110Sstevel@tonic-gate 		 * first message
69120Sstevel@tonic-gate 		 *
69130Sstevel@tonic-gate 		 * If the stream head was at the mark
69140Sstevel@tonic-gate 		 * (STRATMARK) before we dropped sd_lock above
69150Sstevel@tonic-gate 		 * and some data was consumed then we have
69160Sstevel@tonic-gate 		 * moved past the mark thus STRATMARK is
69170Sstevel@tonic-gate 		 * cleared. However, if a message arrived in
69180Sstevel@tonic-gate 		 * strrput during the copyout above causing
69190Sstevel@tonic-gate 		 * STRATMARK to be set we can not clear that
69200Sstevel@tonic-gate 		 * flag.
69210Sstevel@tonic-gate 		 */
69220Sstevel@tonic-gate 		if (type >= QPCTL) {
69230Sstevel@tonic-gate 			ASSERT(type == M_PCPROTO);
69240Sstevel@tonic-gate 			stp->sd_flag &= ~STRPRI;
69250Sstevel@tonic-gate 		}
69260Sstevel@tonic-gate 		if (mark & (MSGMARKNEXT|MSGNOTMARKNEXT|MSGMARK)) {
69270Sstevel@tonic-gate 			if (mark & MSGMARKNEXT) {
69280Sstevel@tonic-gate 				stp->sd_flag &= ~STRNOTATMARK;
69290Sstevel@tonic-gate 				stp->sd_flag |= STRATMARK;
69300Sstevel@tonic-gate 			} else if (mark & MSGNOTMARKNEXT) {
69310Sstevel@tonic-gate 				stp->sd_flag &= ~STRATMARK;
69320Sstevel@tonic-gate 				stp->sd_flag |= STRNOTATMARK;
69330Sstevel@tonic-gate 			} else {
69340Sstevel@tonic-gate 				stp->sd_flag &= ~(STRATMARK|STRNOTATMARK);
69350Sstevel@tonic-gate 			}
69360Sstevel@tonic-gate 		} else if (pr && (old_sd_flag & STRATMARK)) {
69370Sstevel@tonic-gate 			stp->sd_flag &= ~STRATMARK;
69380Sstevel@tonic-gate 		}
69390Sstevel@tonic-gate 	}
69400Sstevel@tonic-gate 
69410Sstevel@tonic-gate 	*flagsp = flg;
69420Sstevel@tonic-gate 	*prip = pri;
69430Sstevel@tonic-gate 
69440Sstevel@tonic-gate 	/*
69450Sstevel@tonic-gate 	 * Getmsg cleanup processing - if the state of the queue has changed
69460Sstevel@tonic-gate 	 * some signals may need to be sent and/or poll awakened.
69470Sstevel@tonic-gate 	 */
69480Sstevel@tonic-gate getmout:
69490Sstevel@tonic-gate 	qbackenable(q, pri);
69500Sstevel@tonic-gate 
69510Sstevel@tonic-gate 	/*
69520Sstevel@tonic-gate 	 * We dropped the stream head lock above. Send all M_SIG messages
69530Sstevel@tonic-gate 	 * before processing stream head for SIGPOLL messages.
69540Sstevel@tonic-gate 	 */
69550Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&stp->sd_lock));
69560Sstevel@tonic-gate 	while ((bp = q->q_first) != NULL &&
69570Sstevel@tonic-gate 	    (bp->b_datap->db_type == M_SIG)) {
69580Sstevel@tonic-gate 		/*
69590Sstevel@tonic-gate 		 * sd_lock is held so the content of the read queue can not
69600Sstevel@tonic-gate 		 * change.
69610Sstevel@tonic-gate 		 */
69620Sstevel@tonic-gate 		bp = getq(q);
69630Sstevel@tonic-gate 		ASSERT(bp != NULL && bp->b_datap->db_type == M_SIG);
69640Sstevel@tonic-gate 
69658752SPeter.Memishian@Sun.COM 		strsignal_nolock(stp, *bp->b_rptr, bp->b_band);
69660Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
69670Sstevel@tonic-gate 		freemsg(bp);
69680Sstevel@tonic-gate 		if (STREAM_NEEDSERVICE(stp))
69690Sstevel@tonic-gate 			stream_runservice(stp);
69700Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
69710Sstevel@tonic-gate 	}
69720Sstevel@tonic-gate 
69730Sstevel@tonic-gate 	/*
69740Sstevel@tonic-gate 	 * stream head cannot change while we make the determination
69750Sstevel@tonic-gate 	 * whether or not to send a signal. Drop the flag to allow strrput
69760Sstevel@tonic-gate 	 * to send firstmsgsigs again.
69770Sstevel@tonic-gate 	 */
69780Sstevel@tonic-gate 	stp->sd_flag &= ~STRGETINPROG;
69790Sstevel@tonic-gate 
69800Sstevel@tonic-gate 	/*
69810Sstevel@tonic-gate 	 * If the type of message at the front of the queue changed
69820Sstevel@tonic-gate 	 * due to the receive the appropriate signals and pollwakeup events
69830Sstevel@tonic-gate 	 * are generated. The type of changes are:
69840Sstevel@tonic-gate 	 *	Processed a hipri message, q_first is not hipri.
69850Sstevel@tonic-gate 	 *	Processed a band X message, and q_first is band Y.
69860Sstevel@tonic-gate 	 * The generated signals and pollwakeups are identical to what
69870Sstevel@tonic-gate 	 * strrput() generates should the message that is now on q_first
69880Sstevel@tonic-gate 	 * arrive to an empty read queue.
69890Sstevel@tonic-gate 	 *
69900Sstevel@tonic-gate 	 * Note: only strrput will send a signal for a hipri message.
69910Sstevel@tonic-gate 	 */
69920Sstevel@tonic-gate 	if ((bp = q->q_first) != NULL && !(stp->sd_flag & STRPRI)) {
69930Sstevel@tonic-gate 		strsigset_t signals = 0;
69940Sstevel@tonic-gate 		strpollset_t pollwakeups = 0;
69950Sstevel@tonic-gate 
69960Sstevel@tonic-gate 		if (flg & MSG_HIPRI) {
69970Sstevel@tonic-gate 			/*
69980Sstevel@tonic-gate 			 * Removed a hipri message. Regular data at
69990Sstevel@tonic-gate 			 * the front of  the queue.
70000Sstevel@tonic-gate 			 */
70010Sstevel@tonic-gate 			if (bp->b_band == 0) {
70020Sstevel@tonic-gate 				signals = S_INPUT | S_RDNORM;
70030Sstevel@tonic-gate 				pollwakeups = POLLIN | POLLRDNORM;
70040Sstevel@tonic-gate 			} else {
70050Sstevel@tonic-gate 				signals = S_INPUT | S_RDBAND;
70060Sstevel@tonic-gate 				pollwakeups = POLLIN | POLLRDBAND;
70070Sstevel@tonic-gate 			}
70080Sstevel@tonic-gate 		} else if (pri != bp->b_band) {
70090Sstevel@tonic-gate 			/*
70100Sstevel@tonic-gate 			 * The band is different for the new q_first.
70110Sstevel@tonic-gate 			 */
70120Sstevel@tonic-gate 			if (bp->b_band == 0) {
70130Sstevel@tonic-gate 				signals = S_RDNORM;
70140Sstevel@tonic-gate 				pollwakeups = POLLIN | POLLRDNORM;
70150Sstevel@tonic-gate 			} else {
70160Sstevel@tonic-gate 				signals = S_RDBAND;
70170Sstevel@tonic-gate 				pollwakeups = POLLIN | POLLRDBAND;
70180Sstevel@tonic-gate 			}
70190Sstevel@tonic-gate 		}
70200Sstevel@tonic-gate 
70210Sstevel@tonic-gate 		if (pollwakeups != 0) {
70220Sstevel@tonic-gate 			if (pollwakeups == (POLLIN | POLLRDNORM)) {
70230Sstevel@tonic-gate 				if (!(stp->sd_rput_opt & SR_POLLIN))
70240Sstevel@tonic-gate 					goto no_pollwake;
70250Sstevel@tonic-gate 				stp->sd_rput_opt &= ~SR_POLLIN;
70260Sstevel@tonic-gate 			}
70270Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
70280Sstevel@tonic-gate 			pollwakeup(&stp->sd_pollist, pollwakeups);
70290Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
70300Sstevel@tonic-gate 		}
70310Sstevel@tonic-gate no_pollwake:
70320Sstevel@tonic-gate 
70330Sstevel@tonic-gate 		if (stp->sd_sigflags & signals)
70340Sstevel@tonic-gate 			strsendsig(stp->sd_siglist, signals, bp->b_band, 0);
70350Sstevel@tonic-gate 	}
70360Sstevel@tonic-gate 	mutex_exit(&stp->sd_lock);
70370Sstevel@tonic-gate 
70380Sstevel@tonic-gate 	rvp->r_val1 = more;
70390Sstevel@tonic-gate 	return (error);
70400Sstevel@tonic-gate #undef	_LASTMARK
70410Sstevel@tonic-gate }
70420Sstevel@tonic-gate 
70430Sstevel@tonic-gate /*
70440Sstevel@tonic-gate  * Get the next message from the read queue.  If the message is
70450Sstevel@tonic-gate  * priority, STRPRI will have been set by strrput().  This flag
70460Sstevel@tonic-gate  * should be reset only when the entire message at the front of the
70470Sstevel@tonic-gate  * queue as been consumed.
70480Sstevel@tonic-gate  *
70490Sstevel@tonic-gate  * If uiop is NULL all data is returned in mctlp.
70500Sstevel@tonic-gate  * Note that a NULL uiop implies that FNDELAY and FNONBLOCK are assumed
70510Sstevel@tonic-gate  * not enabled.
70520Sstevel@tonic-gate  * The timeout parameter is in milliseconds; -1 for infinity.
70530Sstevel@tonic-gate  * This routine handles the consolidation private flags:
70540Sstevel@tonic-gate  *	MSG_IGNERROR	Ignore any stream head error except STPLEX.
70550Sstevel@tonic-gate  *	MSG_DELAYERROR	Defer the error check until the queue is empty.
70560Sstevel@tonic-gate  *	MSG_HOLDSIG	Hold signals while waiting for data.
70570Sstevel@tonic-gate  *	MSG_IPEEK	Only peek at messages.
70580Sstevel@tonic-gate  *	MSG_DISCARDTAIL	Discard the tail M_DATA part of the message
70590Sstevel@tonic-gate  *			that doesn't fit.
70600Sstevel@tonic-gate  *	MSG_NOMARK	If the message is marked leave it on the queue.
70610Sstevel@tonic-gate  *
70620Sstevel@tonic-gate  * NOTE: strgetmsg and kstrgetmsg have much of the logic in common.
70630Sstevel@tonic-gate  */
70640Sstevel@tonic-gate int
kstrgetmsg(struct vnode * vp,mblk_t ** mctlp,struct uio * uiop,unsigned char * prip,int * flagsp,clock_t timout,rval_t * rvp)70650Sstevel@tonic-gate kstrgetmsg(
70660Sstevel@tonic-gate 	struct vnode *vp,
70670Sstevel@tonic-gate 	mblk_t **mctlp,
70680Sstevel@tonic-gate 	struct uio *uiop,
70690Sstevel@tonic-gate 	unsigned char *prip,
70700Sstevel@tonic-gate 	int *flagsp,
70710Sstevel@tonic-gate 	clock_t timout,
70720Sstevel@tonic-gate 	rval_t *rvp)
70730Sstevel@tonic-gate {
70740Sstevel@tonic-gate 	struct stdata *stp;
70750Sstevel@tonic-gate 	mblk_t *bp, *nbp;
70760Sstevel@tonic-gate 	mblk_t *savemp = NULL;
70770Sstevel@tonic-gate 	mblk_t *savemptail = NULL;
70780Sstevel@tonic-gate 	int flags;
70790Sstevel@tonic-gate 	uint_t old_sd_flag;
70800Sstevel@tonic-gate 	int flg;
70810Sstevel@tonic-gate 	int more = 0;
70820Sstevel@tonic-gate 	int error = 0;
70830Sstevel@tonic-gate 	char first = 1;
70840Sstevel@tonic-gate 	uint_t mark;		/* Contains MSG*MARK and _LASTMARK */
70850Sstevel@tonic-gate #define	_LASTMARK	0x8000	/* Distinct from MSG*MARK */
70860Sstevel@tonic-gate 	unsigned char pri = 0;
70870Sstevel@tonic-gate 	queue_t *q;
70880Sstevel@tonic-gate 	int	pr = 0;			/* Partial read successful */
70890Sstevel@tonic-gate 	unsigned char type;
70900Sstevel@tonic-gate 
70910Sstevel@tonic-gate 	TRACE_1(TR_FAC_STREAMS_FR, TR_KSTRGETMSG_ENTER,
70925753Sgww 	    "kstrgetmsg:%p", vp);
70930Sstevel@tonic-gate 
70940Sstevel@tonic-gate 	ASSERT(vp->v_stream);
70950Sstevel@tonic-gate 	stp = vp->v_stream;
70960Sstevel@tonic-gate 	rvp->r_val1 = 0;
70970Sstevel@tonic-gate 
70982712Snn35248 	mutex_enter(&stp->sd_lock);
70992712Snn35248 
71002712Snn35248 	if ((error = i_straccess(stp, JCREAD)) != 0) {
71012712Snn35248 		mutex_exit(&stp->sd_lock);
71022712Snn35248 		return (error);
71032712Snn35248 	}
71040Sstevel@tonic-gate 
71050Sstevel@tonic-gate 	flags = *flagsp;
71060Sstevel@tonic-gate 	if (stp->sd_flag & (STRDERR|STPLEX)) {
71070Sstevel@tonic-gate 		if ((stp->sd_flag & STPLEX) ||
71080Sstevel@tonic-gate 		    (flags & (MSG_IGNERROR|MSG_DELAYERROR)) == 0) {
71090Sstevel@tonic-gate 			error = strgeterr(stp, STRDERR|STPLEX,
71105753Sgww 			    (flags & MSG_IPEEK));
71112712Snn35248 			if (error != 0) {
71122712Snn35248 				mutex_exit(&stp->sd_lock);
71130Sstevel@tonic-gate 				return (error);
71142712Snn35248 			}
71152712Snn35248 		}
71162712Snn35248 	}
71172712Snn35248 	mutex_exit(&stp->sd_lock);
71180Sstevel@tonic-gate 
71190Sstevel@tonic-gate 	switch (flags & (MSG_HIPRI|MSG_ANY|MSG_BAND)) {
71200Sstevel@tonic-gate 	case MSG_HIPRI:
71210Sstevel@tonic-gate 		if (*prip != 0)
71220Sstevel@tonic-gate 			return (EINVAL);
71230Sstevel@tonic-gate 		break;
71240Sstevel@tonic-gate 
71250Sstevel@tonic-gate 	case MSG_ANY:
71260Sstevel@tonic-gate 	case MSG_BAND:
71270Sstevel@tonic-gate 		break;
71280Sstevel@tonic-gate 
71290Sstevel@tonic-gate 	default:
71300Sstevel@tonic-gate 		return (EINVAL);
71310Sstevel@tonic-gate 	}
71320Sstevel@tonic-gate 
71330Sstevel@tonic-gate retry:
71340Sstevel@tonic-gate 	q = _RD(stp->sd_wrq);
71350Sstevel@tonic-gate 	mutex_enter(&stp->sd_lock);
71360Sstevel@tonic-gate 	old_sd_flag = stp->sd_flag;
71370Sstevel@tonic-gate 	mark = 0;
71380Sstevel@tonic-gate 	for (;;) {
71390Sstevel@tonic-gate 		int done = 0;
71400Sstevel@tonic-gate 		int waitflag;
71410Sstevel@tonic-gate 		int fmode;
71420Sstevel@tonic-gate 		mblk_t *q_first = q->q_first;
71430Sstevel@tonic-gate 
71440Sstevel@tonic-gate 		/*
71450Sstevel@tonic-gate 		 * This section of the code operates just like the code
71460Sstevel@tonic-gate 		 * in strgetmsg().  There is a comment there about what
71470Sstevel@tonic-gate 		 * is going on here.
71480Sstevel@tonic-gate 		 */
71490Sstevel@tonic-gate 		if (!(flags & (MSG_HIPRI|MSG_BAND))) {
71500Sstevel@tonic-gate 			/* Asking for normal, band0 data */
71510Sstevel@tonic-gate 			bp = strget(stp, q, uiop, first, &error);
71520Sstevel@tonic-gate 			ASSERT(MUTEX_HELD(&stp->sd_lock));
71530Sstevel@tonic-gate 			if (bp != NULL) {
71548752SPeter.Memishian@Sun.COM 				if (DB_TYPE(bp) == M_SIG) {
71550Sstevel@tonic-gate 					strsignal_nolock(stp, *bp->b_rptr,
71568752SPeter.Memishian@Sun.COM 					    bp->b_band);
71578752SPeter.Memishian@Sun.COM 					freemsg(bp);
71580Sstevel@tonic-gate 					continue;
71590Sstevel@tonic-gate 				} else {
71600Sstevel@tonic-gate 					break;
71610Sstevel@tonic-gate 				}
71620Sstevel@tonic-gate 			}
71630Sstevel@tonic-gate 			if (error != 0) {
71640Sstevel@tonic-gate 				goto getmout;
71650Sstevel@tonic-gate 			}
71660Sstevel@tonic-gate 		/*
71670Sstevel@tonic-gate 		 * We can't depend on the value of STRPRI here because
71680Sstevel@tonic-gate 		 * the stream head may be in transit. Therefore, we
71690Sstevel@tonic-gate 		 * must look at the type of the first message to
71700Sstevel@tonic-gate 		 * determine if a high priority messages is waiting
71710Sstevel@tonic-gate 		 */
71720Sstevel@tonic-gate 		} else if ((flags & MSG_HIPRI) && q_first != NULL &&
71738752SPeter.Memishian@Sun.COM 		    DB_TYPE(q_first) >= QPCTL &&
71746769Sja97890 		    (bp = getq_noenab(q, 0)) != NULL) {
71758752SPeter.Memishian@Sun.COM 			ASSERT(DB_TYPE(bp) >= QPCTL);
71760Sstevel@tonic-gate 			break;
71770Sstevel@tonic-gate 		} else if ((flags & MSG_BAND) && q_first != NULL &&
71788752SPeter.Memishian@Sun.COM 		    ((q_first->b_band >= *prip) || DB_TYPE(q_first) >= QPCTL) &&
71796769Sja97890 		    (bp = getq_noenab(q, 0)) != NULL) {
71800Sstevel@tonic-gate 			/*
71810Sstevel@tonic-gate 			 * Asked for at least band "prip" and got either at
71820Sstevel@tonic-gate 			 * least that band or a hipri message.
71830Sstevel@tonic-gate 			 */
71848752SPeter.Memishian@Sun.COM 			ASSERT(bp->b_band >= *prip || DB_TYPE(bp) >= QPCTL);
71858752SPeter.Memishian@Sun.COM 			if (DB_TYPE(bp) == M_SIG) {
71868752SPeter.Memishian@Sun.COM 				strsignal_nolock(stp, *bp->b_rptr, bp->b_band);
71878752SPeter.Memishian@Sun.COM 				freemsg(bp);
71880Sstevel@tonic-gate 				continue;
71890Sstevel@tonic-gate 			} else {
71900Sstevel@tonic-gate 				break;
71910Sstevel@tonic-gate 			}
71920Sstevel@tonic-gate 		}
71930Sstevel@tonic-gate 
71940Sstevel@tonic-gate 		/* No data. Time to sleep? */
71950Sstevel@tonic-gate 		qbackenable(q, 0);
71960Sstevel@tonic-gate 
71970Sstevel@tonic-gate 		/*
71980Sstevel@tonic-gate 		 * Delayed error notification?
71990Sstevel@tonic-gate 		 */
72000Sstevel@tonic-gate 		if ((stp->sd_flag & (STRDERR|STPLEX)) &&
72010Sstevel@tonic-gate 		    (flags & (MSG_IGNERROR|MSG_DELAYERROR)) == MSG_DELAYERROR) {
72020Sstevel@tonic-gate 			error = strgeterr(stp, STRDERR|STPLEX,
72035753Sgww 			    (flags & MSG_IPEEK));
72040Sstevel@tonic-gate 			if (error != 0) {
72050Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
72060Sstevel@tonic-gate 				return (error);
72070Sstevel@tonic-gate 			}
72080Sstevel@tonic-gate 		}
72090Sstevel@tonic-gate 
72100Sstevel@tonic-gate 		/*
72110Sstevel@tonic-gate 		 * If STRHUP or STREOF, return 0 length control and data.
72120Sstevel@tonic-gate 		 * If a read(fd,buf,0) has been done, do not sleep, just
72130Sstevel@tonic-gate 		 * return.
72140Sstevel@tonic-gate 		 *
72150Sstevel@tonic-gate 		 * If mctlp == NULL and uiop == NULL, then the code will
72160Sstevel@tonic-gate 		 * do the strwaitq. This is an understood way of saying
72170Sstevel@tonic-gate 		 * sleep "polling" until a message is received.
72180Sstevel@tonic-gate 		 */
72190Sstevel@tonic-gate 		if ((stp->sd_flag & (STRHUP|STREOF)) ||
72200Sstevel@tonic-gate 		    (uiop != NULL && uiop->uio_resid == 0)) {
72210Sstevel@tonic-gate 			if (mctlp != NULL)
72220Sstevel@tonic-gate 				*mctlp = NULL;
72230Sstevel@tonic-gate 			*flagsp = 0;
72240Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
72250Sstevel@tonic-gate 			return (0);
72260Sstevel@tonic-gate 		}
72270Sstevel@tonic-gate 
72280Sstevel@tonic-gate 		waitflag = GETWAIT;
72290Sstevel@tonic-gate 		if (flags &
72300Sstevel@tonic-gate 		    (MSG_HOLDSIG|MSG_IGNERROR|MSG_IPEEK|MSG_DELAYERROR)) {
72310Sstevel@tonic-gate 			if (flags & MSG_HOLDSIG)
72320Sstevel@tonic-gate 				waitflag |= STR_NOSIG;
72330Sstevel@tonic-gate 			if (flags & MSG_IGNERROR)
72340Sstevel@tonic-gate 				waitflag |= STR_NOERROR;
72350Sstevel@tonic-gate 			if (flags & MSG_IPEEK)
72360Sstevel@tonic-gate 				waitflag |= STR_PEEK;
72370Sstevel@tonic-gate 			if (flags & MSG_DELAYERROR)
72380Sstevel@tonic-gate 				waitflag |= STR_DELAYERR;
72390Sstevel@tonic-gate 		}
72400Sstevel@tonic-gate 		if (uiop != NULL)
72410Sstevel@tonic-gate 			fmode = uiop->uio_fmode;
72420Sstevel@tonic-gate 		else
72430Sstevel@tonic-gate 			fmode = 0;
72440Sstevel@tonic-gate 
72450Sstevel@tonic-gate 		TRACE_2(TR_FAC_STREAMS_FR, TR_KSTRGETMSG_WAIT,
72465753Sgww 		    "kstrgetmsg calls strwaitq:%p, %p",
72475753Sgww 		    vp, uiop);
72480Sstevel@tonic-gate 		if (((error = strwaitq(stp, waitflag, (ssize_t)0,
72496707Sbrutus 		    fmode, timout, &done))) != 0 || done) {
72500Sstevel@tonic-gate 			TRACE_2(TR_FAC_STREAMS_FR, TR_KSTRGETMSG_DONE,
72515753Sgww 			    "kstrgetmsg error or done:%p, %p",
72525753Sgww 			    vp, uiop);
72530Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
72540Sstevel@tonic-gate 			return (error);
72550Sstevel@tonic-gate 		}
72560Sstevel@tonic-gate 		TRACE_2(TR_FAC_STREAMS_FR, TR_KSTRGETMSG_AWAKE,
72575753Sgww 		    "kstrgetmsg awakes:%p, %p", vp, uiop);
72582712Snn35248 		if ((error = i_straccess(stp, JCREAD)) != 0) {
72590Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
72602712Snn35248 			return (error);
72610Sstevel@tonic-gate 		}
72620Sstevel@tonic-gate 		first = 0;
72630Sstevel@tonic-gate 	}
72640Sstevel@tonic-gate 	ASSERT(bp != NULL);
72650Sstevel@tonic-gate 	/*
72660Sstevel@tonic-gate 	 * Extract any mark information. If the message is not completely
72670Sstevel@tonic-gate 	 * consumed this information will be put in the mblk
72680Sstevel@tonic-gate 	 * that is putback.
72690Sstevel@tonic-gate 	 * If MSGMARKNEXT is set and the message is completely consumed
72700Sstevel@tonic-gate 	 * the STRATMARK flag will be set below. Likewise, if
72710Sstevel@tonic-gate 	 * MSGNOTMARKNEXT is set and the message is
72720Sstevel@tonic-gate 	 * completely consumed STRNOTATMARK will be set.
72730Sstevel@tonic-gate 	 */
72740Sstevel@tonic-gate 	mark = bp->b_flag & (MSGMARK | MSGMARKNEXT | MSGNOTMARKNEXT);
72750Sstevel@tonic-gate 	ASSERT((mark & (MSGMARKNEXT|MSGNOTMARKNEXT)) !=
72765753Sgww 	    (MSGMARKNEXT|MSGNOTMARKNEXT));
72770Sstevel@tonic-gate 	pri = bp->b_band;
72780Sstevel@tonic-gate 	if (mark != 0) {
72790Sstevel@tonic-gate 		/*
72800Sstevel@tonic-gate 		 * If the caller doesn't want the mark return.
72810Sstevel@tonic-gate 		 * Used to implement MSG_WAITALL in sockets.
72820Sstevel@tonic-gate 		 */
72830Sstevel@tonic-gate 		if (flags & MSG_NOMARK) {
72840Sstevel@tonic-gate 			putback(stp, q, bp, pri);
72850Sstevel@tonic-gate 			qbackenable(q, pri);
72860Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
72870Sstevel@tonic-gate 			return (EWOULDBLOCK);
72880Sstevel@tonic-gate 		}
72890Sstevel@tonic-gate 		if (bp == stp->sd_mark) {
72900Sstevel@tonic-gate 			mark |= _LASTMARK;
72910Sstevel@tonic-gate 			stp->sd_mark = NULL;
72920Sstevel@tonic-gate 		}
72930Sstevel@tonic-gate 	}
72940Sstevel@tonic-gate 
72950Sstevel@tonic-gate 	/*
72960Sstevel@tonic-gate 	 * keep track of the first message type
72970Sstevel@tonic-gate 	 */
72980Sstevel@tonic-gate 	type = bp->b_datap->db_type;
72990Sstevel@tonic-gate 
73000Sstevel@tonic-gate 	if (bp->b_datap->db_type == M_PASSFP) {
73010Sstevel@tonic-gate 		if ((mark & _LASTMARK) && (stp->sd_mark == NULL))
73020Sstevel@tonic-gate 			stp->sd_mark = bp;
73030Sstevel@tonic-gate 		bp->b_flag |= mark & ~_LASTMARK;
73040Sstevel@tonic-gate 		putback(stp, q, bp, pri);
73050Sstevel@tonic-gate 		qbackenable(q, pri);
73060Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
73070Sstevel@tonic-gate 		return (EBADMSG);
73080Sstevel@tonic-gate 	}
73090Sstevel@tonic-gate 	ASSERT(type != M_SIG);
73100Sstevel@tonic-gate 
73110Sstevel@tonic-gate 	if (flags & MSG_IPEEK) {
73120Sstevel@tonic-gate 		/*
73130Sstevel@tonic-gate 		 * Clear any struioflag - we do the uiomove over again
73140Sstevel@tonic-gate 		 * when peeking since it simplifies the code.
73150Sstevel@tonic-gate 		 *
73160Sstevel@tonic-gate 		 * Dup the message and put the original back on the queue.
73170Sstevel@tonic-gate 		 * If dupmsg() fails, try again with copymsg() to see if
73180Sstevel@tonic-gate 		 * there is indeed a shortage of memory.  dupmsg() may fail
73190Sstevel@tonic-gate 		 * if db_ref in any of the messages reaches its limit.
73200Sstevel@tonic-gate 		 */
73216707Sbrutus 
73220Sstevel@tonic-gate 		if ((nbp = dupmsg(bp)) == NULL && (nbp = copymsg(bp)) == NULL) {
73230Sstevel@tonic-gate 			/*
73240Sstevel@tonic-gate 			 * Restore the state of the stream head since we
73250Sstevel@tonic-gate 			 * need to drop sd_lock (strwaitbuf is sleeping).
73260Sstevel@tonic-gate 			 */
73270Sstevel@tonic-gate 			size_t size = msgdsize(bp);
73280Sstevel@tonic-gate 
73290Sstevel@tonic-gate 			if ((mark & _LASTMARK) && (stp->sd_mark == NULL))
73300Sstevel@tonic-gate 				stp->sd_mark = bp;
73310Sstevel@tonic-gate 			bp->b_flag |= mark & ~_LASTMARK;
73320Sstevel@tonic-gate 			putback(stp, q, bp, pri);
73330Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
73340Sstevel@tonic-gate 			error = strwaitbuf(size, BPRI_HI);
73350Sstevel@tonic-gate 			if (error) {
73360Sstevel@tonic-gate 				/*
73370Sstevel@tonic-gate 				 * There is no net change to the queue thus
73380Sstevel@tonic-gate 				 * no need to qbackenable.
73390Sstevel@tonic-gate 				 */
73400Sstevel@tonic-gate 				return (error);
73410Sstevel@tonic-gate 			}
73420Sstevel@tonic-gate 			goto retry;
73430Sstevel@tonic-gate 		}
73440Sstevel@tonic-gate 
73450Sstevel@tonic-gate 		if ((mark & _LASTMARK) && (stp->sd_mark == NULL))
73460Sstevel@tonic-gate 			stp->sd_mark = bp;
73470Sstevel@tonic-gate 		bp->b_flag |= mark & ~_LASTMARK;
73480Sstevel@tonic-gate 		putback(stp, q, bp, pri);
73490Sstevel@tonic-gate 		bp = nbp;
73500Sstevel@tonic-gate 	}
73510Sstevel@tonic-gate 
73520Sstevel@tonic-gate 	/*
73530Sstevel@tonic-gate 	 * Set this flag so strrput will not generate signals. Need to
73540Sstevel@tonic-gate 	 * make sure this flag is cleared before leaving this routine
73550Sstevel@tonic-gate 	 * else signals will stop being sent.
73560Sstevel@tonic-gate 	 */
73570Sstevel@tonic-gate 	stp->sd_flag |= STRGETINPROG;
73580Sstevel@tonic-gate 	mutex_exit(&stp->sd_lock);
73590Sstevel@tonic-gate 
73605850Svk199839 	if ((stp->sd_rputdatafunc != NULL) && (DB_TYPE(bp) == M_DATA)) {
73615850Svk199839 		mblk_t *tmp, *prevmp;
73625850Svk199839 
73635850Svk199839 		/*
73645850Svk199839 		 * Put first non-data mblk back to stream head and
73655850Svk199839 		 * cut the mblk chain so sd_rputdatafunc only sees
73665850Svk199839 		 * M_DATA mblks. We can skip the first mblk since it
73675850Svk199839 		 * is M_DATA according to the condition above.
73685850Svk199839 		 */
73695850Svk199839 		for (prevmp = bp, tmp = bp->b_cont; tmp != NULL;
73705850Svk199839 		    prevmp = tmp, tmp = tmp->b_cont) {
73715850Svk199839 			if (DB_TYPE(tmp) != M_DATA) {
73725850Svk199839 				prevmp->b_cont = NULL;
73735850Svk199839 				mutex_enter(&stp->sd_lock);
73745850Svk199839 				putback(stp, q, tmp, tmp->b_band);
73755850Svk199839 				mutex_exit(&stp->sd_lock);
73765850Svk199839 				break;
73775850Svk199839 			}
73785850Svk199839 		}
73795850Svk199839 
73805850Svk199839 		bp = (stp->sd_rputdatafunc)(stp->sd_vnode, bp,
73815850Svk199839 		    NULL, NULL, NULL, NULL);
7382898Skais 
7383898Skais 		if (bp == NULL)
7384898Skais 			goto retry;
7385898Skais 	}
7386898Skais 
73870Sstevel@tonic-gate 	if (STREAM_NEEDSERVICE(stp))
73880Sstevel@tonic-gate 		stream_runservice(stp);
73890Sstevel@tonic-gate 
73900Sstevel@tonic-gate 	/*
73910Sstevel@tonic-gate 	 * Set HIPRI flag if message is priority.
73920Sstevel@tonic-gate 	 */
73930Sstevel@tonic-gate 	if (type >= QPCTL)
73940Sstevel@tonic-gate 		flg = MSG_HIPRI;
73950Sstevel@tonic-gate 	else
73960Sstevel@tonic-gate 		flg = MSG_BAND;
73970Sstevel@tonic-gate 
73980Sstevel@tonic-gate 	/*
73990Sstevel@tonic-gate 	 * First process PROTO or PCPROTO blocks, if any.
74000Sstevel@tonic-gate 	 */
74010Sstevel@tonic-gate 	if (mctlp != NULL && type != M_DATA) {
74020Sstevel@tonic-gate 		mblk_t *nbp;
74030Sstevel@tonic-gate 
74040Sstevel@tonic-gate 		*mctlp = bp;
74050Sstevel@tonic-gate 		while (bp->b_cont && bp->b_cont->b_datap->db_type != M_DATA)
74060Sstevel@tonic-gate 			bp = bp->b_cont;
74070Sstevel@tonic-gate 		nbp = bp->b_cont;
74080Sstevel@tonic-gate 		bp->b_cont = NULL;
74090Sstevel@tonic-gate 		bp = nbp;
74100Sstevel@tonic-gate 	}
74110Sstevel@tonic-gate 
74120Sstevel@tonic-gate 	if (bp && bp->b_datap->db_type != M_DATA) {
74130Sstevel@tonic-gate 		/*
74140Sstevel@tonic-gate 		 * More PROTO blocks in msg. Will only happen if mctlp is NULL.
74150Sstevel@tonic-gate 		 */
74160Sstevel@tonic-gate 		more |= MORECTL;
74170Sstevel@tonic-gate 		savemp = bp;
74180Sstevel@tonic-gate 		while (bp && bp->b_datap->db_type != M_DATA) {
74190Sstevel@tonic-gate 			savemptail = bp;
74200Sstevel@tonic-gate 			bp = bp->b_cont;
74210Sstevel@tonic-gate 		}
74220Sstevel@tonic-gate 		savemptail->b_cont = NULL;
74230Sstevel@tonic-gate 	}
74240Sstevel@tonic-gate 
74250Sstevel@tonic-gate 	/*
74260Sstevel@tonic-gate 	 * Now process DATA blocks, if any.
74270Sstevel@tonic-gate 	 */
74280Sstevel@tonic-gate 	if (uiop == NULL) {
74290Sstevel@tonic-gate 		/* Append data to tail of mctlp */
74306707Sbrutus 
74310Sstevel@tonic-gate 		if (mctlp != NULL) {
74320Sstevel@tonic-gate 			mblk_t **mpp = mctlp;
74330Sstevel@tonic-gate 
74340Sstevel@tonic-gate 			while (*mpp != NULL)
74350Sstevel@tonic-gate 				mpp = &((*mpp)->b_cont);
74360Sstevel@tonic-gate 			*mpp = bp;
74370Sstevel@tonic-gate 			bp = NULL;
74380Sstevel@tonic-gate 		}
74390Sstevel@tonic-gate 	} else if (uiop->uio_resid >= 0 && bp) {
74400Sstevel@tonic-gate 		size_t oldresid = uiop->uio_resid;
74410Sstevel@tonic-gate 
74420Sstevel@tonic-gate 		/*
74430Sstevel@tonic-gate 		 * If a streams message is likely to consist
74440Sstevel@tonic-gate 		 * of many small mblks, it is pulled up into
74450Sstevel@tonic-gate 		 * one continuous chunk of memory.
74469171Sxiuyan.wang@Sun.COM 		 * The size of the first mblk may be bogus because
74479171Sxiuyan.wang@Sun.COM 		 * successive read() calls on the socket reduce
74489171Sxiuyan.wang@Sun.COM 		 * the size of this mblk until it is exhausted
74499171Sxiuyan.wang@Sun.COM 		 * and then the code walks on to the next. Thus
74509171Sxiuyan.wang@Sun.COM 		 * the size of the mblk may not be the original size
74519171Sxiuyan.wang@Sun.COM 		 * that was passed up, it's simply a remainder
74529171Sxiuyan.wang@Sun.COM 		 * and hence can be very small without any
74539171Sxiuyan.wang@Sun.COM 		 * implication that the packet is badly fragmented.
74549171Sxiuyan.wang@Sun.COM 		 * So the size of the possible second mblk is
74559171Sxiuyan.wang@Sun.COM 		 * used to spot a badly fragmented packet.
74560Sstevel@tonic-gate 		 * see longer comment at top of page
74570Sstevel@tonic-gate 		 * by mblk_pull_len declaration.
74580Sstevel@tonic-gate 		 */
74590Sstevel@tonic-gate 
74609171Sxiuyan.wang@Sun.COM 		if (bp->b_cont != NULL && MBLKL(bp->b_cont) < mblk_pull_len) {
74610Sstevel@tonic-gate 			(void) pullupmsg(bp, -1);
74620Sstevel@tonic-gate 		}
74630Sstevel@tonic-gate 
74640Sstevel@tonic-gate 		bp = struiocopyout(bp, uiop, &error);
74650Sstevel@tonic-gate 		if (error != 0) {
74660Sstevel@tonic-gate 			if (mctlp != NULL) {
74670Sstevel@tonic-gate 				freemsg(*mctlp);
74680Sstevel@tonic-gate 				*mctlp = NULL;
74690Sstevel@tonic-gate 			} else
74700Sstevel@tonic-gate 				freemsg(savemp);
74710Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
74720Sstevel@tonic-gate 			/*
74730Sstevel@tonic-gate 			 * clear stream head hi pri flag based on
74740Sstevel@tonic-gate 			 * first message
74750Sstevel@tonic-gate 			 */
74760Sstevel@tonic-gate 			if (!(flags & MSG_IPEEK) && (type >= QPCTL)) {
74770Sstevel@tonic-gate 				ASSERT(type == M_PCPROTO);
74780Sstevel@tonic-gate 				stp->sd_flag &= ~STRPRI;
74790Sstevel@tonic-gate 			}
74800Sstevel@tonic-gate 			more = 0;
74810Sstevel@tonic-gate 			goto getmout;
74820Sstevel@tonic-gate 		}
74830Sstevel@tonic-gate 		/*
74840Sstevel@tonic-gate 		 * (pr == 1) indicates a partial read.
74850Sstevel@tonic-gate 		 */
74860Sstevel@tonic-gate 		if (oldresid > uiop->uio_resid)
74870Sstevel@tonic-gate 			pr = 1;
74880Sstevel@tonic-gate 	}
74890Sstevel@tonic-gate 
74900Sstevel@tonic-gate 	if (bp) {			/* more data blocks in msg */
74910Sstevel@tonic-gate 		more |= MOREDATA;
74920Sstevel@tonic-gate 		if (savemp)
74930Sstevel@tonic-gate 			savemptail->b_cont = bp;
74940Sstevel@tonic-gate 		else
74950Sstevel@tonic-gate 			savemp = bp;
74960Sstevel@tonic-gate 	}
74970Sstevel@tonic-gate 
74980Sstevel@tonic-gate 	mutex_enter(&stp->sd_lock);
74990Sstevel@tonic-gate 	if (savemp) {
75000Sstevel@tonic-gate 		if (flags & (MSG_IPEEK|MSG_DISCARDTAIL)) {
75010Sstevel@tonic-gate 			/*
75020Sstevel@tonic-gate 			 * When MSG_DISCARDTAIL is set or
75030Sstevel@tonic-gate 			 * when peeking discard any tail. When peeking this
75040Sstevel@tonic-gate 			 * is the tail of the dup that was copied out - the
75050Sstevel@tonic-gate 			 * message has already been putback on the queue.
75060Sstevel@tonic-gate 			 * Return MOREDATA to the caller even though the data
75070Sstevel@tonic-gate 			 * is discarded. This is used by sockets (to
75080Sstevel@tonic-gate 			 * set MSG_TRUNC).
75090Sstevel@tonic-gate 			 */
75100Sstevel@tonic-gate 			freemsg(savemp);
75110Sstevel@tonic-gate 			if (!(flags & MSG_IPEEK) && (type >= QPCTL)) {
75120Sstevel@tonic-gate 				ASSERT(type == M_PCPROTO);
75130Sstevel@tonic-gate 				stp->sd_flag &= ~STRPRI;
75140Sstevel@tonic-gate 			}
75150Sstevel@tonic-gate 		} else if (pr && (savemp->b_datap->db_type == M_DATA) &&
75165753Sgww 		    msgnodata(savemp)) {
75170Sstevel@tonic-gate 			/*
75180Sstevel@tonic-gate 			 * Avoid queuing a zero-length tail part of
75190Sstevel@tonic-gate 			 * a message. pr=1 indicates that we read some of
75200Sstevel@tonic-gate 			 * the message.
75210Sstevel@tonic-gate 			 */
75220Sstevel@tonic-gate 			freemsg(savemp);
75230Sstevel@tonic-gate 			more &= ~MOREDATA;
75240Sstevel@tonic-gate 			if (type >= QPCTL) {
75250Sstevel@tonic-gate 				ASSERT(type == M_PCPROTO);
75260Sstevel@tonic-gate 				stp->sd_flag &= ~STRPRI;
75270Sstevel@tonic-gate 			}
75280Sstevel@tonic-gate 		} else {
75290Sstevel@tonic-gate 			savemp->b_band = pri;
75300Sstevel@tonic-gate 			/*
75310Sstevel@tonic-gate 			 * If the first message was HIPRI and the one we're
75320Sstevel@tonic-gate 			 * putting back isn't, then clear STRPRI, otherwise
75330Sstevel@tonic-gate 			 * set STRPRI again.  Note that we must set STRPRI
75340Sstevel@tonic-gate 			 * again since the flush logic in strrput_nondata()
75350Sstevel@tonic-gate 			 * may have cleared it while we had sd_lock dropped.
75360Sstevel@tonic-gate 			 */
75376707Sbrutus 
75380Sstevel@tonic-gate 			if (type >= QPCTL) {
75390Sstevel@tonic-gate 				ASSERT(type == M_PCPROTO);
75400Sstevel@tonic-gate 				if (queclass(savemp) < QPCTL)
75410Sstevel@tonic-gate 					stp->sd_flag &= ~STRPRI;
75420Sstevel@tonic-gate 				else
75430Sstevel@tonic-gate 					stp->sd_flag |= STRPRI;
75440Sstevel@tonic-gate 			} else if (queclass(savemp) >= QPCTL) {
75450Sstevel@tonic-gate 				/*
75460Sstevel@tonic-gate 				 * The first message was not a HIPRI message,
75470Sstevel@tonic-gate 				 * but the one we are about to putback is.
75480Sstevel@tonic-gate 				 * For simplicitly, we do not allow for HIPRI
75490Sstevel@tonic-gate 				 * messages to be embedded in the message
75500Sstevel@tonic-gate 				 * body, so just force it to same type as
75510Sstevel@tonic-gate 				 * first message.
75520Sstevel@tonic-gate 				 */
75530Sstevel@tonic-gate 				ASSERT(type == M_DATA || type == M_PROTO);
75540Sstevel@tonic-gate 				ASSERT(savemp->b_datap->db_type == M_PCPROTO);
75550Sstevel@tonic-gate 				savemp->b_datap->db_type = type;
75560Sstevel@tonic-gate 			}
75570Sstevel@tonic-gate 			if (mark != 0) {
75580Sstevel@tonic-gate 				if ((mark & _LASTMARK) &&
75590Sstevel@tonic-gate 				    (stp->sd_mark == NULL)) {
75600Sstevel@tonic-gate 					/*
75610Sstevel@tonic-gate 					 * If another marked message arrived
75620Sstevel@tonic-gate 					 * while sd_lock was not held sd_mark
75630Sstevel@tonic-gate 					 * would be non-NULL.
75640Sstevel@tonic-gate 					 */
75650Sstevel@tonic-gate 					stp->sd_mark = savemp;
75660Sstevel@tonic-gate 				}
75670Sstevel@tonic-gate 				savemp->b_flag |= mark & ~_LASTMARK;
75680Sstevel@tonic-gate 			}
75690Sstevel@tonic-gate 			putback(stp, q, savemp, pri);
75700Sstevel@tonic-gate 		}
75710Sstevel@tonic-gate 	} else if (!(flags & MSG_IPEEK)) {
75720Sstevel@tonic-gate 		/*
75730Sstevel@tonic-gate 		 * The complete message was consumed.
75740Sstevel@tonic-gate 		 *
75750Sstevel@tonic-gate 		 * If another M_PCPROTO arrived while sd_lock was not held
75760Sstevel@tonic-gate 		 * it would have been discarded since STRPRI was still set.
75770Sstevel@tonic-gate 		 *
75780Sstevel@tonic-gate 		 * Move the MSG*MARKNEXT information
75790Sstevel@tonic-gate 		 * to the stream head just in case
75800Sstevel@tonic-gate 		 * the read queue becomes empty.
75810Sstevel@tonic-gate 		 * clear stream head hi pri flag based on
75820Sstevel@tonic-gate 		 * first message
75830Sstevel@tonic-gate 		 *
75840Sstevel@tonic-gate 		 * If the stream head was at the mark
75850Sstevel@tonic-gate 		 * (STRATMARK) before we dropped sd_lock above
75860Sstevel@tonic-gate 		 * and some data was consumed then we have
75870Sstevel@tonic-gate 		 * moved past the mark thus STRATMARK is
75880Sstevel@tonic-gate 		 * cleared. However, if a message arrived in
75890Sstevel@tonic-gate 		 * strrput during the copyout above causing
75900Sstevel@tonic-gate 		 * STRATMARK to be set we can not clear that
75910Sstevel@tonic-gate 		 * flag.
75920Sstevel@tonic-gate 		 * XXX A "perimeter" would help by single-threading strrput,
75930Sstevel@tonic-gate 		 * strread, strgetmsg and kstrgetmsg.
75940Sstevel@tonic-gate 		 */
75950Sstevel@tonic-gate 		if (type >= QPCTL) {
75960Sstevel@tonic-gate 			ASSERT(type == M_PCPROTO);
75970Sstevel@tonic-gate 			stp->sd_flag &= ~STRPRI;
75980Sstevel@tonic-gate 		}
75990Sstevel@tonic-gate 		if (mark & (MSGMARKNEXT|MSGNOTMARKNEXT|MSGMARK)) {
76000Sstevel@tonic-gate 			if (mark & MSGMARKNEXT) {
76010Sstevel@tonic-gate 				stp->sd_flag &= ~STRNOTATMARK;
76020Sstevel@tonic-gate 				stp->sd_flag |= STRATMARK;
76030Sstevel@tonic-gate 			} else if (mark & MSGNOTMARKNEXT) {
76040Sstevel@tonic-gate 				stp->sd_flag &= ~STRATMARK;
76050Sstevel@tonic-gate 				stp->sd_flag |= STRNOTATMARK;
76060Sstevel@tonic-gate 			} else {
76070Sstevel@tonic-gate 				stp->sd_flag &= ~(STRATMARK|STRNOTATMARK);
76080Sstevel@tonic-gate 			}
76090Sstevel@tonic-gate 		} else if (pr && (old_sd_flag & STRATMARK)) {
76100Sstevel@tonic-gate 			stp->sd_flag &= ~STRATMARK;
76110Sstevel@tonic-gate 		}
76120Sstevel@tonic-gate 	}
76130Sstevel@tonic-gate 
76140Sstevel@tonic-gate 	*flagsp = flg;
76150Sstevel@tonic-gate 	*prip = pri;
76160Sstevel@tonic-gate 
76170Sstevel@tonic-gate 	/*
76180Sstevel@tonic-gate 	 * Getmsg cleanup processing - if the state of the queue has changed
76190Sstevel@tonic-gate 	 * some signals may need to be sent and/or poll awakened.
76200Sstevel@tonic-gate 	 */
76210Sstevel@tonic-gate getmout:
76220Sstevel@tonic-gate 	qbackenable(q, pri);
76230Sstevel@tonic-gate 
76240Sstevel@tonic-gate 	/*
76250Sstevel@tonic-gate 	 * We dropped the stream head lock above. Send all M_SIG messages
76260Sstevel@tonic-gate 	 * before processing stream head for SIGPOLL messages.
76270Sstevel@tonic-gate 	 */
76280Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&stp->sd_lock));
76290Sstevel@tonic-gate 	while ((bp = q->q_first) != NULL &&
76300Sstevel@tonic-gate 	    (bp->b_datap->db_type == M_SIG)) {
76310Sstevel@tonic-gate 		/*
76320Sstevel@tonic-gate 		 * sd_lock is held so the content of the read queue can not
76330Sstevel@tonic-gate 		 * change.
76340Sstevel@tonic-gate 		 */
76350Sstevel@tonic-gate 		bp = getq(q);
76360Sstevel@tonic-gate 		ASSERT(bp != NULL && bp->b_datap->db_type == M_SIG);
76370Sstevel@tonic-gate 
76388752SPeter.Memishian@Sun.COM 		strsignal_nolock(stp, *bp->b_rptr, bp->b_band);
76390Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
76400Sstevel@tonic-gate 		freemsg(bp);
76410Sstevel@tonic-gate 		if (STREAM_NEEDSERVICE(stp))
76420Sstevel@tonic-gate 			stream_runservice(stp);
76430Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
76440Sstevel@tonic-gate 	}
76450Sstevel@tonic-gate 
76460Sstevel@tonic-gate 	/*
76470Sstevel@tonic-gate 	 * stream head cannot change while we make the determination
76480Sstevel@tonic-gate 	 * whether or not to send a signal. Drop the flag to allow strrput
76490Sstevel@tonic-gate 	 * to send firstmsgsigs again.
76500Sstevel@tonic-gate 	 */
76510Sstevel@tonic-gate 	stp->sd_flag &= ~STRGETINPROG;
76520Sstevel@tonic-gate 
76530Sstevel@tonic-gate 	/*
76540Sstevel@tonic-gate 	 * If the type of message at the front of the queue changed
76550Sstevel@tonic-gate 	 * due to the receive the appropriate signals and pollwakeup events
76560Sstevel@tonic-gate 	 * are generated. The type of changes are:
76570Sstevel@tonic-gate 	 *	Processed a hipri message, q_first is not hipri.
76580Sstevel@tonic-gate 	 *	Processed a band X message, and q_first is band Y.
76590Sstevel@tonic-gate 	 * The generated signals and pollwakeups are identical to what
76600Sstevel@tonic-gate 	 * strrput() generates should the message that is now on q_first
76610Sstevel@tonic-gate 	 * arrive to an empty read queue.
76620Sstevel@tonic-gate 	 *
76630Sstevel@tonic-gate 	 * Note: only strrput will send a signal for a hipri message.
76640Sstevel@tonic-gate 	 */
76650Sstevel@tonic-gate 	if ((bp = q->q_first) != NULL && !(stp->sd_flag & STRPRI)) {
76660Sstevel@tonic-gate 		strsigset_t signals = 0;
76670Sstevel@tonic-gate 		strpollset_t pollwakeups = 0;
76680Sstevel@tonic-gate 
76690Sstevel@tonic-gate 		if (flg & MSG_HIPRI) {
76700Sstevel@tonic-gate 			/*
76710Sstevel@tonic-gate 			 * Removed a hipri message. Regular data at
76720Sstevel@tonic-gate 			 * the front of  the queue.
76730Sstevel@tonic-gate 			 */
76740Sstevel@tonic-gate 			if (bp->b_band == 0) {
76750Sstevel@tonic-gate 				signals = S_INPUT | S_RDNORM;
76760Sstevel@tonic-gate 				pollwakeups = POLLIN | POLLRDNORM;
76770Sstevel@tonic-gate 			} else {
76780Sstevel@tonic-gate 				signals = S_INPUT | S_RDBAND;
76790Sstevel@tonic-gate 				pollwakeups = POLLIN | POLLRDBAND;
76800Sstevel@tonic-gate 			}
76810Sstevel@tonic-gate 		} else if (pri != bp->b_band) {
76820Sstevel@tonic-gate 			/*
76830Sstevel@tonic-gate 			 * The band is different for the new q_first.
76840Sstevel@tonic-gate 			 */
76850Sstevel@tonic-gate 			if (bp->b_band == 0) {
76860Sstevel@tonic-gate 				signals = S_RDNORM;
76870Sstevel@tonic-gate 				pollwakeups = POLLIN | POLLRDNORM;
76880Sstevel@tonic-gate 			} else {
76890Sstevel@tonic-gate 				signals = S_RDBAND;
76900Sstevel@tonic-gate 				pollwakeups = POLLIN | POLLRDBAND;
76910Sstevel@tonic-gate 			}
76920Sstevel@tonic-gate 		}
76930Sstevel@tonic-gate 
76940Sstevel@tonic-gate 		if (pollwakeups != 0) {
76950Sstevel@tonic-gate 			if (pollwakeups == (POLLIN | POLLRDNORM)) {
76960Sstevel@tonic-gate 				if (!(stp->sd_rput_opt & SR_POLLIN))
76970Sstevel@tonic-gate 					goto no_pollwake;
76980Sstevel@tonic-gate 				stp->sd_rput_opt &= ~SR_POLLIN;
76990Sstevel@tonic-gate 			}
77000Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
77010Sstevel@tonic-gate 			pollwakeup(&stp->sd_pollist, pollwakeups);
77020Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
77030Sstevel@tonic-gate 		}
77040Sstevel@tonic-gate no_pollwake:
77050Sstevel@tonic-gate 
77060Sstevel@tonic-gate 		if (stp->sd_sigflags & signals)
77070Sstevel@tonic-gate 			strsendsig(stp->sd_siglist, signals, bp->b_band, 0);
77080Sstevel@tonic-gate 	}
77090Sstevel@tonic-gate 	mutex_exit(&stp->sd_lock);
77100Sstevel@tonic-gate 
77110Sstevel@tonic-gate 	rvp->r_val1 = more;
77120Sstevel@tonic-gate 	return (error);
77130Sstevel@tonic-gate #undef	_LASTMARK
77140Sstevel@tonic-gate }
77150Sstevel@tonic-gate 
77160Sstevel@tonic-gate /*
77170Sstevel@tonic-gate  * Put a message downstream.
77180Sstevel@tonic-gate  *
77190Sstevel@tonic-gate  * NOTE: strputmsg and kstrputmsg have much of the logic in common.
77200Sstevel@tonic-gate  */
77210Sstevel@tonic-gate int
strputmsg(struct vnode * vp,struct strbuf * mctl,struct strbuf * mdata,unsigned char pri,int flag,int fmode)77220Sstevel@tonic-gate strputmsg(
77230Sstevel@tonic-gate 	struct vnode *vp,
77240Sstevel@tonic-gate 	struct strbuf *mctl,
77250Sstevel@tonic-gate 	struct strbuf *mdata,
77260Sstevel@tonic-gate 	unsigned char pri,
77270Sstevel@tonic-gate 	int flag,
77280Sstevel@tonic-gate 	int fmode)
77290Sstevel@tonic-gate {
77300Sstevel@tonic-gate 	struct stdata *stp;
77310Sstevel@tonic-gate 	queue_t *wqp;
77320Sstevel@tonic-gate 	mblk_t *mp;
77330Sstevel@tonic-gate 	ssize_t msgsize;
77340Sstevel@tonic-gate 	ssize_t rmin, rmax;
77350Sstevel@tonic-gate 	int error;
77360Sstevel@tonic-gate 	struct uio uios;
77370Sstevel@tonic-gate 	struct uio *uiop = &uios;
77380Sstevel@tonic-gate 	struct iovec iovs;
77390Sstevel@tonic-gate 	int xpg4 = 0;
77400Sstevel@tonic-gate 
77410Sstevel@tonic-gate 	ASSERT(vp->v_stream);
77420Sstevel@tonic-gate 	stp = vp->v_stream;
77430Sstevel@tonic-gate 	wqp = stp->sd_wrq;
77440Sstevel@tonic-gate 
77450Sstevel@tonic-gate 	/*
77460Sstevel@tonic-gate 	 * If it is an XPG4 application, we need to send
77470Sstevel@tonic-gate 	 * SIGPIPE below
77480Sstevel@tonic-gate 	 */
77490Sstevel@tonic-gate 
77500Sstevel@tonic-gate 	xpg4 = (flag & MSG_XPG4) ? 1 : 0;
77510Sstevel@tonic-gate 	flag &= ~MSG_XPG4;
77520Sstevel@tonic-gate 
775311861SMarek.Pospisil@Sun.COM 	if (AU_AUDITING())
77540Sstevel@tonic-gate 		audit_strputmsg(vp, mctl, mdata, pri, flag, fmode);
77550Sstevel@tonic-gate 
77562712Snn35248 	mutex_enter(&stp->sd_lock);
77572712Snn35248 
77582712Snn35248 	if ((error = i_straccess(stp, JCWRITE)) != 0) {
77592712Snn35248 		mutex_exit(&stp->sd_lock);
77602712Snn35248 		return (error);
77612712Snn35248 	}
77620Sstevel@tonic-gate 
77630Sstevel@tonic-gate 	if (stp->sd_flag & (STWRERR|STRHUP|STPLEX)) {
77640Sstevel@tonic-gate 		error = strwriteable(stp, B_FALSE, xpg4);
77652712Snn35248 		if (error != 0) {
77662712Snn35248 			mutex_exit(&stp->sd_lock);
77670Sstevel@tonic-gate 			return (error);
77682712Snn35248 		}
77692712Snn35248 	}
77702712Snn35248 
77712712Snn35248 	mutex_exit(&stp->sd_lock);
77720Sstevel@tonic-gate 
77730Sstevel@tonic-gate 	/*
77740Sstevel@tonic-gate 	 * Check for legal flag value.
77750Sstevel@tonic-gate 	 */
77760Sstevel@tonic-gate 	switch (flag) {
77770Sstevel@tonic-gate 	case MSG_HIPRI:
77780Sstevel@tonic-gate 		if ((mctl->len < 0) || (pri != 0))
77790Sstevel@tonic-gate 			return (EINVAL);
77800Sstevel@tonic-gate 		break;
77810Sstevel@tonic-gate 	case MSG_BAND:
77820Sstevel@tonic-gate 		break;
77830Sstevel@tonic-gate 
77840Sstevel@tonic-gate 	default:
77850Sstevel@tonic-gate 		return (EINVAL);
77860Sstevel@tonic-gate 	}
77870Sstevel@tonic-gate 
77880Sstevel@tonic-gate 	TRACE_1(TR_FAC_STREAMS_FR, TR_STRPUTMSG_IN,
77895753Sgww 	    "strputmsg in:stp %p", stp);
77900Sstevel@tonic-gate 
77910Sstevel@tonic-gate 	/* get these values from those cached in the stream head */
77920Sstevel@tonic-gate 	rmin = stp->sd_qn_minpsz;
77930Sstevel@tonic-gate 	rmax = stp->sd_qn_maxpsz;
77940Sstevel@tonic-gate 
77950Sstevel@tonic-gate 	/*
77960Sstevel@tonic-gate 	 * Make sure ctl and data sizes together fall within the
77970Sstevel@tonic-gate 	 * limits of the max and min receive packet sizes and do
77980Sstevel@tonic-gate 	 * not exceed system limit.
77990Sstevel@tonic-gate 	 */
78000Sstevel@tonic-gate 	ASSERT((rmax >= 0) || (rmax == INFPSZ));
78010Sstevel@tonic-gate 	if (rmax == 0) {
78020Sstevel@tonic-gate 		return (ERANGE);
78030Sstevel@tonic-gate 	}
78040Sstevel@tonic-gate 	/*
78050Sstevel@tonic-gate 	 * Use the MAXIMUM of sd_maxblk and q_maxpsz.
78060Sstevel@tonic-gate 	 * Needed to prevent partial failures in the strmakedata loop.
78070Sstevel@tonic-gate 	 */
78080Sstevel@tonic-gate 	if (stp->sd_maxblk != INFPSZ && rmax != INFPSZ && rmax < stp->sd_maxblk)
78090Sstevel@tonic-gate 		rmax = stp->sd_maxblk;
78100Sstevel@tonic-gate 
78110Sstevel@tonic-gate 	if ((msgsize = mdata->len) < 0) {
78120Sstevel@tonic-gate 		msgsize = 0;
78130Sstevel@tonic-gate 		rmin = 0;	/* no range check for NULL data part */
78140Sstevel@tonic-gate 	}
78150Sstevel@tonic-gate 	if ((msgsize < rmin) ||
78160Sstevel@tonic-gate 	    ((msgsize > rmax) && (rmax != INFPSZ)) ||
78170Sstevel@tonic-gate 	    (mctl->len > strctlsz)) {
78180Sstevel@tonic-gate 		return (ERANGE);
78190Sstevel@tonic-gate 	}
78200Sstevel@tonic-gate 
78210Sstevel@tonic-gate 	/*
78220Sstevel@tonic-gate 	 * Setup uio and iov for data part
78230Sstevel@tonic-gate 	 */
78240Sstevel@tonic-gate 	iovs.iov_base = mdata->buf;
78250Sstevel@tonic-gate 	iovs.iov_len = msgsize;
78260Sstevel@tonic-gate 	uios.uio_iov = &iovs;
78270Sstevel@tonic-gate 	uios.uio_iovcnt = 1;
78280Sstevel@tonic-gate 	uios.uio_loffset = 0;
78290Sstevel@tonic-gate 	uios.uio_segflg = UIO_USERSPACE;
78300Sstevel@tonic-gate 	uios.uio_fmode = fmode;
78310Sstevel@tonic-gate 	uios.uio_extflg = UIO_COPY_DEFAULT;
78320Sstevel@tonic-gate 	uios.uio_resid = msgsize;
78330Sstevel@tonic-gate 	uios.uio_offset = 0;
78340Sstevel@tonic-gate 
78350Sstevel@tonic-gate 	/* Ignore flow control in strput for HIPRI */
78360Sstevel@tonic-gate 	if (flag & MSG_HIPRI)
78370Sstevel@tonic-gate 		flag |= MSG_IGNFLOW;
78380Sstevel@tonic-gate 
78390Sstevel@tonic-gate 	for (;;) {
78400Sstevel@tonic-gate 		int done = 0;
78410Sstevel@tonic-gate 
78420Sstevel@tonic-gate 		/*
78430Sstevel@tonic-gate 		 * strput will always free the ctl mblk - even when strput
78440Sstevel@tonic-gate 		 * fails.
78450Sstevel@tonic-gate 		 */
78460Sstevel@tonic-gate 		if ((error = strmakectl(mctl, flag, fmode, &mp)) != 0) {
78470Sstevel@tonic-gate 			TRACE_3(TR_FAC_STREAMS_FR, TR_STRPUTMSG_OUT,
78485753Sgww 			    "strputmsg out:stp %p out %d error %d",
78495753Sgww 			    stp, 1, error);
78500Sstevel@tonic-gate 			return (error);
78510Sstevel@tonic-gate 		}
78520Sstevel@tonic-gate 		/*
78530Sstevel@tonic-gate 		 * Verify that the whole message can be transferred by
78540Sstevel@tonic-gate 		 * strput.
78550Sstevel@tonic-gate 		 */
78560Sstevel@tonic-gate 		ASSERT(stp->sd_maxblk == INFPSZ ||
78575753Sgww 		    stp->sd_maxblk >= mdata->len);
78580Sstevel@tonic-gate 
78590Sstevel@tonic-gate 		msgsize = mdata->len;
78600Sstevel@tonic-gate 		error = strput(stp, mp, uiop, &msgsize, 0, pri, flag);
78610Sstevel@tonic-gate 		mdata->len = msgsize;
78620Sstevel@tonic-gate 
78630Sstevel@tonic-gate 		if (error == 0)
78640Sstevel@tonic-gate 			break;
78650Sstevel@tonic-gate 
78660Sstevel@tonic-gate 		if (error != EWOULDBLOCK)
78670Sstevel@tonic-gate 			goto out;
78680Sstevel@tonic-gate 
78690Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
78700Sstevel@tonic-gate 		/*
78710Sstevel@tonic-gate 		 * Check for a missed wakeup.
78720Sstevel@tonic-gate 		 * Needed since strput did not hold sd_lock across
78730Sstevel@tonic-gate 		 * the canputnext.
78740Sstevel@tonic-gate 		 */
78750Sstevel@tonic-gate 		if (bcanputnext(wqp, pri)) {
78760Sstevel@tonic-gate 			/* Try again */
78770Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
78780Sstevel@tonic-gate 			continue;
78790Sstevel@tonic-gate 		}
78800Sstevel@tonic-gate 		TRACE_2(TR_FAC_STREAMS_FR, TR_STRPUTMSG_WAIT,
78815753Sgww 		    "strputmsg wait:stp %p waits pri %d", stp, pri);
78820Sstevel@tonic-gate 		if (((error = strwaitq(stp, WRITEWAIT, (ssize_t)0, fmode, -1,
78830Sstevel@tonic-gate 		    &done)) != 0) || done) {
78840Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
78850Sstevel@tonic-gate 			TRACE_3(TR_FAC_STREAMS_FR, TR_STRPUTMSG_OUT,
78865753Sgww 			    "strputmsg out:q %p out %d error %d",
78875753Sgww 			    stp, 0, error);
78880Sstevel@tonic-gate 			return (error);
78890Sstevel@tonic-gate 		}
78900Sstevel@tonic-gate 		TRACE_1(TR_FAC_STREAMS_FR, TR_STRPUTMSG_WAKE,
78915753Sgww 		    "strputmsg wake:stp %p wakes", stp);
78922712Snn35248 		if ((error = i_straccess(stp, JCWRITE)) != 0) {
78932712Snn35248 			mutex_exit(&stp->sd_lock);
78942712Snn35248 			return (error);
78952712Snn35248 		}
78960Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
78970Sstevel@tonic-gate 	}
78980Sstevel@tonic-gate out:
78990Sstevel@tonic-gate 	/*
79000Sstevel@tonic-gate 	 * For historic reasons, applications expect EAGAIN
79010Sstevel@tonic-gate 	 * when data mblk could not be allocated. so change
79020Sstevel@tonic-gate 	 * ENOMEM back to EAGAIN
79030Sstevel@tonic-gate 	 */
79040Sstevel@tonic-gate 	if (error == ENOMEM)
79050Sstevel@tonic-gate 		error = EAGAIN;
79060Sstevel@tonic-gate 	TRACE_3(TR_FAC_STREAMS_FR, TR_STRPUTMSG_OUT,
79075753Sgww 	    "strputmsg out:stp %p out %d error %d", stp, 2, error);
79080Sstevel@tonic-gate 	return (error);
79090Sstevel@tonic-gate }
79100Sstevel@tonic-gate 
79110Sstevel@tonic-gate /*
79120Sstevel@tonic-gate  * Put a message downstream.
79130Sstevel@tonic-gate  * Can send only an M_PROTO/M_PCPROTO by passing in a NULL uiop.
79140Sstevel@tonic-gate  * The fmode flag (NDELAY, NONBLOCK) is the or of the flags in the uio
79150Sstevel@tonic-gate  * and the fmode parameter.
79160Sstevel@tonic-gate  *
79170Sstevel@tonic-gate  * This routine handles the consolidation private flags:
79180Sstevel@tonic-gate  *	MSG_IGNERROR	Ignore any stream head error except STPLEX.
79190Sstevel@tonic-gate  *	MSG_HOLDSIG	Hold signals while waiting for data.
79200Sstevel@tonic-gate  *	MSG_IGNFLOW	Don't check streams flow control.
79210Sstevel@tonic-gate  *
79220Sstevel@tonic-gate  * NOTE: strputmsg and kstrputmsg have much of the logic in common.
79230Sstevel@tonic-gate  */
79240Sstevel@tonic-gate int
kstrputmsg(struct vnode * vp,mblk_t * mctl,struct uio * uiop,ssize_t msgsize,unsigned char pri,int flag,int fmode)79250Sstevel@tonic-gate kstrputmsg(
79260Sstevel@tonic-gate 	struct vnode *vp,
79270Sstevel@tonic-gate 	mblk_t *mctl,
79280Sstevel@tonic-gate 	struct uio *uiop,
79290Sstevel@tonic-gate 	ssize_t msgsize,
79300Sstevel@tonic-gate 	unsigned char pri,
79310Sstevel@tonic-gate 	int flag,
79320Sstevel@tonic-gate 	int fmode)
79330Sstevel@tonic-gate {
79340Sstevel@tonic-gate 	struct stdata *stp;
79350Sstevel@tonic-gate 	queue_t *wqp;
79360Sstevel@tonic-gate 	ssize_t rmin, rmax;
79370Sstevel@tonic-gate 	int error;
79380Sstevel@tonic-gate 
79390Sstevel@tonic-gate 	ASSERT(vp->v_stream);
79400Sstevel@tonic-gate 	stp = vp->v_stream;
79410Sstevel@tonic-gate 	wqp = stp->sd_wrq;
794211861SMarek.Pospisil@Sun.COM 	if (AU_AUDITING())
79430Sstevel@tonic-gate 		audit_strputmsg(vp, NULL, NULL, pri, flag, fmode);
7944577Smeem 	if (mctl == NULL)
7945577Smeem 		return (EINVAL);
79460Sstevel@tonic-gate 
79472712Snn35248 	mutex_enter(&stp->sd_lock);
79482712Snn35248 
79492712Snn35248 	if ((error = i_straccess(stp, JCWRITE)) != 0) {
79502712Snn35248 		mutex_exit(&stp->sd_lock);
79512712Snn35248 		freemsg(mctl);
79522712Snn35248 		return (error);
79530Sstevel@tonic-gate 	}
79540Sstevel@tonic-gate 
79550Sstevel@tonic-gate 	if ((stp->sd_flag & STPLEX) || !(flag & MSG_IGNERROR)) {
79560Sstevel@tonic-gate 		if (stp->sd_flag & (STWRERR|STRHUP|STPLEX)) {
79570Sstevel@tonic-gate 			error = strwriteable(stp, B_FALSE, B_TRUE);
79580Sstevel@tonic-gate 			if (error != 0) {
79592712Snn35248 				mutex_exit(&stp->sd_lock);
79600Sstevel@tonic-gate 				freemsg(mctl);
79610Sstevel@tonic-gate 				return (error);
79620Sstevel@tonic-gate 			}
79630Sstevel@tonic-gate 		}
79640Sstevel@tonic-gate 	}
79650Sstevel@tonic-gate 
79662712Snn35248 	mutex_exit(&stp->sd_lock);
79672712Snn35248 
79680Sstevel@tonic-gate 	/*
79690Sstevel@tonic-gate 	 * Check for legal flag value.
79700Sstevel@tonic-gate 	 */
79710Sstevel@tonic-gate 	switch (flag & (MSG_HIPRI|MSG_BAND|MSG_ANY)) {
79720Sstevel@tonic-gate 	case MSG_HIPRI:
7973577Smeem 		if (pri != 0) {
79740Sstevel@tonic-gate 			freemsg(mctl);
79750Sstevel@tonic-gate 			return (EINVAL);
79760Sstevel@tonic-gate 		}
79770Sstevel@tonic-gate 		break;
79780Sstevel@tonic-gate 	case MSG_BAND:
79790Sstevel@tonic-gate 		break;
79800Sstevel@tonic-gate 	default:
79810Sstevel@tonic-gate 		freemsg(mctl);
79820Sstevel@tonic-gate 		return (EINVAL);
79830Sstevel@tonic-gate 	}
79840Sstevel@tonic-gate 
79850Sstevel@tonic-gate 	TRACE_1(TR_FAC_STREAMS_FR, TR_KSTRPUTMSG_IN,
79865753Sgww 	    "kstrputmsg in:stp %p", stp);
79870Sstevel@tonic-gate 
79880Sstevel@tonic-gate 	/* get these values from those cached in the stream head */
79890Sstevel@tonic-gate 	rmin = stp->sd_qn_minpsz;
79900Sstevel@tonic-gate 	rmax = stp->sd_qn_maxpsz;
79910Sstevel@tonic-gate 
79920Sstevel@tonic-gate 	/*
79930Sstevel@tonic-gate 	 * Make sure ctl and data sizes together fall within the
79940Sstevel@tonic-gate 	 * limits of the max and min receive packet sizes and do
79950Sstevel@tonic-gate 	 * not exceed system limit.
79960Sstevel@tonic-gate 	 */
79970Sstevel@tonic-gate 	ASSERT((rmax >= 0) || (rmax == INFPSZ));
79980Sstevel@tonic-gate 	if (rmax == 0) {
79990Sstevel@tonic-gate 		freemsg(mctl);
80000Sstevel@tonic-gate 		return (ERANGE);
80010Sstevel@tonic-gate 	}
80020Sstevel@tonic-gate 	/*
80030Sstevel@tonic-gate 	 * Use the MAXIMUM of sd_maxblk and q_maxpsz.
80040Sstevel@tonic-gate 	 * Needed to prevent partial failures in the strmakedata loop.
80050Sstevel@tonic-gate 	 */
80060Sstevel@tonic-gate 	if (stp->sd_maxblk != INFPSZ && rmax != INFPSZ && rmax < stp->sd_maxblk)
80070Sstevel@tonic-gate 		rmax = stp->sd_maxblk;
80080Sstevel@tonic-gate 
80090Sstevel@tonic-gate 	if (uiop == NULL) {
80100Sstevel@tonic-gate 		msgsize = -1;
80110Sstevel@tonic-gate 		rmin = -1;	/* no range check for NULL data part */
80120Sstevel@tonic-gate 	} else {
80130Sstevel@tonic-gate 		/* Use uio flags as well as the fmode parameter flags */
80140Sstevel@tonic-gate 		fmode |= uiop->uio_fmode;
80150Sstevel@tonic-gate 
80160Sstevel@tonic-gate 		if ((msgsize < rmin) ||
80170Sstevel@tonic-gate 		    ((msgsize > rmax) && (rmax != INFPSZ))) {
80180Sstevel@tonic-gate 			freemsg(mctl);
80190Sstevel@tonic-gate 			return (ERANGE);
80200Sstevel@tonic-gate 		}
80210Sstevel@tonic-gate 	}
80220Sstevel@tonic-gate 
80230Sstevel@tonic-gate 	/* Ignore flow control in strput for HIPRI */
80240Sstevel@tonic-gate 	if (flag & MSG_HIPRI)
80250Sstevel@tonic-gate 		flag |= MSG_IGNFLOW;
80260Sstevel@tonic-gate 
80270Sstevel@tonic-gate 	for (;;) {
80280Sstevel@tonic-gate 		int done = 0;
80290Sstevel@tonic-gate 		int waitflag;
80300Sstevel@tonic-gate 		mblk_t *mp;
80310Sstevel@tonic-gate 
80320Sstevel@tonic-gate 		/*
80330Sstevel@tonic-gate 		 * strput will always free the ctl mblk - even when strput
80340Sstevel@tonic-gate 		 * fails. If MSG_IGNFLOW is set then any error returned
80350Sstevel@tonic-gate 		 * will cause us to break the loop, so we don't need a copy
80360Sstevel@tonic-gate 		 * of the message. If MSG_IGNFLOW is not set, then we can
80370Sstevel@tonic-gate 		 * get hit by flow control and be forced to try again. In
80380Sstevel@tonic-gate 		 * this case we need to have a copy of the message. We
80390Sstevel@tonic-gate 		 * do this using copymsg since the message may get modified
80400Sstevel@tonic-gate 		 * by something below us.
80410Sstevel@tonic-gate 		 *
80420Sstevel@tonic-gate 		 * We've observed that many TPI providers do not check db_ref
80430Sstevel@tonic-gate 		 * on the control messages but blindly reuse them for the
80440Sstevel@tonic-gate 		 * T_OK_ACK/T_ERROR_ACK. Thus using copymsg is more
80450Sstevel@tonic-gate 		 * friendly to such providers than using dupmsg. Also, note
80460Sstevel@tonic-gate 		 * that sockfs uses MSG_IGNFLOW for all TPI control messages.
80470Sstevel@tonic-gate 		 * Only data messages are subject to flow control, hence
80480Sstevel@tonic-gate 		 * subject to this copymsg.
80490Sstevel@tonic-gate 		 */
80500Sstevel@tonic-gate 		if (flag & MSG_IGNFLOW) {
80510Sstevel@tonic-gate 			mp = mctl;
80520Sstevel@tonic-gate 			mctl = NULL;
80530Sstevel@tonic-gate 		} else {
80540Sstevel@tonic-gate 			do {
80550Sstevel@tonic-gate 				/*
80560Sstevel@tonic-gate 				 * If a message has a free pointer, the message
80570Sstevel@tonic-gate 				 * must be dupmsg to maintain this pointer.
80580Sstevel@tonic-gate 				 * Code using this facility must be sure
80590Sstevel@tonic-gate 				 * that modules below will not change the
80600Sstevel@tonic-gate 				 * contents of the dblk without checking db_ref
80610Sstevel@tonic-gate 				 * first. If db_ref is > 1, then the module
80620Sstevel@tonic-gate 				 * needs to do a copymsg first. Otherwise,
80630Sstevel@tonic-gate 				 * the contents of the dblk may become
80640Sstevel@tonic-gate 				 * inconsistent because the freesmg/freeb below
80650Sstevel@tonic-gate 				 * may end up calling atomic_add_32_nv.
80660Sstevel@tonic-gate 				 * The atomic_add_32_nv in freeb (accessing
80670Sstevel@tonic-gate 				 * all of db_ref, db_type, db_flags, and
80680Sstevel@tonic-gate 				 * db_struioflag) does not prevent other threads
80690Sstevel@tonic-gate 				 * from concurrently trying to modify e.g.
80700Sstevel@tonic-gate 				 * db_type.
80710Sstevel@tonic-gate 				 */
80720Sstevel@tonic-gate 				if (mctl->b_datap->db_frtnp != NULL)
80730Sstevel@tonic-gate 					mp = dupmsg(mctl);
80740Sstevel@tonic-gate 				else
80750Sstevel@tonic-gate 					mp = copymsg(mctl);
80760Sstevel@tonic-gate 
8077577Smeem 				if (mp != NULL)
80780Sstevel@tonic-gate 					break;
80790Sstevel@tonic-gate 
80800Sstevel@tonic-gate 				error = strwaitbuf(msgdsize(mctl), BPRI_MED);
80810Sstevel@tonic-gate 				if (error) {
80820Sstevel@tonic-gate 					freemsg(mctl);
80830Sstevel@tonic-gate 					return (error);
80840Sstevel@tonic-gate 				}
80850Sstevel@tonic-gate 			} while (mp == NULL);
80860Sstevel@tonic-gate 		}
80870Sstevel@tonic-gate 		/*
80880Sstevel@tonic-gate 		 * Verify that all of msgsize can be transferred by
80890Sstevel@tonic-gate 		 * strput.
80900Sstevel@tonic-gate 		 */
8091577Smeem 		ASSERT(stp->sd_maxblk == INFPSZ || stp->sd_maxblk >= msgsize);
80920Sstevel@tonic-gate 		error = strput(stp, mp, uiop, &msgsize, 0, pri, flag);
80930Sstevel@tonic-gate 		if (error == 0)
80940Sstevel@tonic-gate 			break;
80950Sstevel@tonic-gate 
80960Sstevel@tonic-gate 		if (error != EWOULDBLOCK)
80970Sstevel@tonic-gate 			goto out;
80980Sstevel@tonic-gate 
80990Sstevel@tonic-gate 		/*
81000Sstevel@tonic-gate 		 * IF MSG_IGNFLOW is set we should have broken out of loop
81010Sstevel@tonic-gate 		 * above.
81020Sstevel@tonic-gate 		 */
81030Sstevel@tonic-gate 		ASSERT(!(flag & MSG_IGNFLOW));
81040Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
81050Sstevel@tonic-gate 		/*
81060Sstevel@tonic-gate 		 * Check for a missed wakeup.
81070Sstevel@tonic-gate 		 * Needed since strput did not hold sd_lock across
81080Sstevel@tonic-gate 		 * the canputnext.
81090Sstevel@tonic-gate 		 */
81100Sstevel@tonic-gate 		if (bcanputnext(wqp, pri)) {
81110Sstevel@tonic-gate 			/* Try again */
81120Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
81130Sstevel@tonic-gate 			continue;
81140Sstevel@tonic-gate 		}
81150Sstevel@tonic-gate 		TRACE_2(TR_FAC_STREAMS_FR, TR_KSTRPUTMSG_WAIT,
81165753Sgww 		    "kstrputmsg wait:stp %p waits pri %d", stp, pri);
81170Sstevel@tonic-gate 
81180Sstevel@tonic-gate 		waitflag = WRITEWAIT;
81190Sstevel@tonic-gate 		if (flag & (MSG_HOLDSIG|MSG_IGNERROR)) {
81200Sstevel@tonic-gate 			if (flag & MSG_HOLDSIG)
81210Sstevel@tonic-gate 				waitflag |= STR_NOSIG;
81220Sstevel@tonic-gate 			if (flag & MSG_IGNERROR)
81230Sstevel@tonic-gate 				waitflag |= STR_NOERROR;
81240Sstevel@tonic-gate 		}
81250Sstevel@tonic-gate 		if (((error = strwaitq(stp, waitflag,
81260Sstevel@tonic-gate 		    (ssize_t)0, fmode, -1, &done)) != 0) || done) {
81270Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
81280Sstevel@tonic-gate 			TRACE_3(TR_FAC_STREAMS_FR, TR_KSTRPUTMSG_OUT,
81295753Sgww 			    "kstrputmsg out:stp %p out %d error %d",
81305753Sgww 			    stp, 0, error);
81310Sstevel@tonic-gate 			freemsg(mctl);
81320Sstevel@tonic-gate 			return (error);
81330Sstevel@tonic-gate 		}
81340Sstevel@tonic-gate 		TRACE_1(TR_FAC_STREAMS_FR, TR_KSTRPUTMSG_WAKE,
81355753Sgww 		    "kstrputmsg wake:stp %p wakes", stp);
81362712Snn35248 		if ((error = i_straccess(stp, JCWRITE)) != 0) {
81372712Snn35248 			mutex_exit(&stp->sd_lock);
81382712Snn35248 			freemsg(mctl);
81392712Snn35248 			return (error);
81402712Snn35248 		}
81410Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
81420Sstevel@tonic-gate 	}
81430Sstevel@tonic-gate out:
81440Sstevel@tonic-gate 	freemsg(mctl);
81450Sstevel@tonic-gate 	/*
81460Sstevel@tonic-gate 	 * For historic reasons, applications expect EAGAIN
81470Sstevel@tonic-gate 	 * when data mblk could not be allocated. so change
81480Sstevel@tonic-gate 	 * ENOMEM back to EAGAIN
81490Sstevel@tonic-gate 	 */
81500Sstevel@tonic-gate 	if (error == ENOMEM)
81510Sstevel@tonic-gate 		error = EAGAIN;
81520Sstevel@tonic-gate 	TRACE_3(TR_FAC_STREAMS_FR, TR_KSTRPUTMSG_OUT,
81535753Sgww 	    "kstrputmsg out:stp %p out %d error %d", stp, 2, error);
81540Sstevel@tonic-gate 	return (error);
81550Sstevel@tonic-gate }
81560Sstevel@tonic-gate 
81570Sstevel@tonic-gate /*
81580Sstevel@tonic-gate  * Determines whether the necessary conditions are set on a stream
81590Sstevel@tonic-gate  * for it to be readable, writeable, or have exceptions.
81600Sstevel@tonic-gate  *
81610Sstevel@tonic-gate  * strpoll handles the consolidation private events:
81620Sstevel@tonic-gate  *	POLLNOERR	Do not return POLLERR even if there are stream
81630Sstevel@tonic-gate  *			head errors.
81640Sstevel@tonic-gate  *			Used by sockfs.
81650Sstevel@tonic-gate  *	POLLRDDATA	Do not return POLLIN unless at least one message on
81660Sstevel@tonic-gate  *			the queue contains one or more M_DATA mblks. Thus
81670Sstevel@tonic-gate  *			when this flag is set a queue with only
81680Sstevel@tonic-gate  *			M_PROTO/M_PCPROTO mblks does not return POLLIN.
81690Sstevel@tonic-gate  *			Used by sockfs to ignore T_EXDATA_IND messages.
81700Sstevel@tonic-gate  *
81710Sstevel@tonic-gate  * Note: POLLRDDATA assumes that synch streams only return messages with
81720Sstevel@tonic-gate  * an M_DATA attached (i.e. not messages consisting of only
81730Sstevel@tonic-gate  * an M_PROTO/M_PCPROTO part).
81740Sstevel@tonic-gate  */
81750Sstevel@tonic-gate int
strpoll(struct stdata * stp,short events_arg,int anyyet,short * reventsp,struct pollhead ** phpp)81760Sstevel@tonic-gate strpoll(
81770Sstevel@tonic-gate 	struct stdata *stp,
81780Sstevel@tonic-gate 	short events_arg,
81790Sstevel@tonic-gate 	int anyyet,
81800Sstevel@tonic-gate 	short *reventsp,
81810Sstevel@tonic-gate 	struct pollhead **phpp)
81820Sstevel@tonic-gate {
81830Sstevel@tonic-gate 	int events = (ushort_t)events_arg;
81840Sstevel@tonic-gate 	int retevents = 0;
81850Sstevel@tonic-gate 	mblk_t *mp;
81860Sstevel@tonic-gate 	qband_t *qbp;
81870Sstevel@tonic-gate 	long sd_flags = stp->sd_flag;
81880Sstevel@tonic-gate 	int headlocked = 0;
81890Sstevel@tonic-gate 
81900Sstevel@tonic-gate 	/*
81910Sstevel@tonic-gate 	 * For performance, a single 'if' tests for most possible edge
81920Sstevel@tonic-gate 	 * conditions in one shot
81930Sstevel@tonic-gate 	 */
81940Sstevel@tonic-gate 	if (sd_flags & (STPLEX | STRDERR | STWRERR)) {
81950Sstevel@tonic-gate 		if (sd_flags & STPLEX) {
81960Sstevel@tonic-gate 			*reventsp = POLLNVAL;
81970Sstevel@tonic-gate 			return (EINVAL);
81980Sstevel@tonic-gate 		}
81990Sstevel@tonic-gate 		if (((events & (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)) &&
82000Sstevel@tonic-gate 		    (sd_flags & STRDERR)) ||
82010Sstevel@tonic-gate 		    ((events & (POLLOUT | POLLWRNORM | POLLWRBAND)) &&
82020Sstevel@tonic-gate 		    (sd_flags & STWRERR))) {
82030Sstevel@tonic-gate 			if (!(events & POLLNOERR)) {
82040Sstevel@tonic-gate 				*reventsp = POLLERR;
82050Sstevel@tonic-gate 				return (0);
82060Sstevel@tonic-gate 			}
82070Sstevel@tonic-gate 		}
82080Sstevel@tonic-gate 	}
82090Sstevel@tonic-gate 	if (sd_flags & STRHUP) {
82100Sstevel@tonic-gate 		retevents |= POLLHUP;
82110Sstevel@tonic-gate 	} else if (events & (POLLWRNORM | POLLWRBAND)) {
82120Sstevel@tonic-gate 		queue_t *tq;
82130Sstevel@tonic-gate 		queue_t	*qp = stp->sd_wrq;
82140Sstevel@tonic-gate 
82150Sstevel@tonic-gate 		claimstr(qp);
82160Sstevel@tonic-gate 		/* Find next module forward that has a service procedure */
82170Sstevel@tonic-gate 		tq = qp->q_next->q_nfsrv;
82180Sstevel@tonic-gate 		ASSERT(tq != NULL);
82190Sstevel@tonic-gate 
82200Sstevel@tonic-gate 		polllock(&stp->sd_pollist, QLOCK(tq));
82210Sstevel@tonic-gate 		if (events & POLLWRNORM) {
82220Sstevel@tonic-gate 			queue_t *sqp;
82230Sstevel@tonic-gate 
82240Sstevel@tonic-gate 			if (tq->q_flag & QFULL)
82250Sstevel@tonic-gate 				/* ensure backq svc procedure runs */
82260Sstevel@tonic-gate 				tq->q_flag |= QWANTW;
82270Sstevel@tonic-gate 			else if ((sqp = stp->sd_struiowrq) != NULL) {
82280Sstevel@tonic-gate 				/* Check sync stream barrier write q */
82290Sstevel@tonic-gate 				mutex_exit(QLOCK(tq));
82300Sstevel@tonic-gate 				polllock(&stp->sd_pollist, QLOCK(sqp));
82310Sstevel@tonic-gate 				if (sqp->q_flag & QFULL)
82320Sstevel@tonic-gate 					/* ensure pollwakeup() is done */
82330Sstevel@tonic-gate 					sqp->q_flag |= QWANTWSYNC;
82340Sstevel@tonic-gate 				else
82350Sstevel@tonic-gate 					retevents |= POLLOUT;
82360Sstevel@tonic-gate 				/* More write events to process ??? */
82370Sstevel@tonic-gate 				if (! (events & POLLWRBAND)) {
82380Sstevel@tonic-gate 					mutex_exit(QLOCK(sqp));
82390Sstevel@tonic-gate 					releasestr(qp);
82400Sstevel@tonic-gate 					goto chkrd;
82410Sstevel@tonic-gate 				}
82420Sstevel@tonic-gate 				mutex_exit(QLOCK(sqp));
82430Sstevel@tonic-gate 				polllock(&stp->sd_pollist, QLOCK(tq));
82440Sstevel@tonic-gate 			} else
82450Sstevel@tonic-gate 				retevents |= POLLOUT;
82460Sstevel@tonic-gate 		}
82470Sstevel@tonic-gate 		if (events & POLLWRBAND) {
82480Sstevel@tonic-gate 			qbp = tq->q_bandp;
82490Sstevel@tonic-gate 			if (qbp) {
82500Sstevel@tonic-gate 				while (qbp) {
82510Sstevel@tonic-gate 					if (qbp->qb_flag & QB_FULL)
82520Sstevel@tonic-gate 						qbp->qb_flag |= QB_WANTW;
82530Sstevel@tonic-gate 					else
82540Sstevel@tonic-gate 						retevents |= POLLWRBAND;
82550Sstevel@tonic-gate 					qbp = qbp->qb_next;
82560Sstevel@tonic-gate 				}
82570Sstevel@tonic-gate 			} else {
82580Sstevel@tonic-gate 				retevents |= POLLWRBAND;
82590Sstevel@tonic-gate 			}
82600Sstevel@tonic-gate 		}
82610Sstevel@tonic-gate 		mutex_exit(QLOCK(tq));
82620Sstevel@tonic-gate 		releasestr(qp);
82630Sstevel@tonic-gate 	}
82640Sstevel@tonic-gate chkrd:
82650Sstevel@tonic-gate 	if (sd_flags & STRPRI) {
82660Sstevel@tonic-gate 		retevents |= (events & POLLPRI);
82670Sstevel@tonic-gate 	} else if (events & (POLLRDNORM | POLLRDBAND | POLLIN)) {
82680Sstevel@tonic-gate 		queue_t	*qp = _RD(stp->sd_wrq);
82690Sstevel@tonic-gate 		int normevents = (events & (POLLIN | POLLRDNORM));
82700Sstevel@tonic-gate 
82710Sstevel@tonic-gate 		/*
82720Sstevel@tonic-gate 		 * Note: Need to do polllock() here since ps_lock may be
82730Sstevel@tonic-gate 		 * held. See bug 4191544.
82740Sstevel@tonic-gate 		 */
82750Sstevel@tonic-gate 		polllock(&stp->sd_pollist, &stp->sd_lock);
82760Sstevel@tonic-gate 		headlocked = 1;
82770Sstevel@tonic-gate 		mp = qp->q_first;
82780Sstevel@tonic-gate 		while (mp) {
82790Sstevel@tonic-gate 			/*
82800Sstevel@tonic-gate 			 * For POLLRDDATA we scan b_cont and b_next until we
82810Sstevel@tonic-gate 			 * find an M_DATA.
82820Sstevel@tonic-gate 			 */
82830Sstevel@tonic-gate 			if ((events & POLLRDDATA) &&
82840Sstevel@tonic-gate 			    mp->b_datap->db_type != M_DATA) {
82850Sstevel@tonic-gate 				mblk_t *nmp = mp->b_cont;
82860Sstevel@tonic-gate 
82870Sstevel@tonic-gate 				while (nmp != NULL &&
82880Sstevel@tonic-gate 				    nmp->b_datap->db_type != M_DATA)
82890Sstevel@tonic-gate 					nmp = nmp->b_cont;
82900Sstevel@tonic-gate 				if (nmp == NULL) {
82910Sstevel@tonic-gate 					mp = mp->b_next;
82920Sstevel@tonic-gate 					continue;
82930Sstevel@tonic-gate 				}
82940Sstevel@tonic-gate 			}
82950Sstevel@tonic-gate 			if (mp->b_band == 0)
82960Sstevel@tonic-gate 				retevents |= normevents;
82970Sstevel@tonic-gate 			else
82980Sstevel@tonic-gate 				retevents |= (events & (POLLIN | POLLRDBAND));
82990Sstevel@tonic-gate 			break;
83000Sstevel@tonic-gate 		}
83010Sstevel@tonic-gate 		if (! (retevents & normevents) &&
83020Sstevel@tonic-gate 		    (stp->sd_wakeq & RSLEEP)) {
83030Sstevel@tonic-gate 			/*
83040Sstevel@tonic-gate 			 * Sync stream barrier read queue has data.
83050Sstevel@tonic-gate 			 */
83060Sstevel@tonic-gate 			retevents |= normevents;
83070Sstevel@tonic-gate 		}
83080Sstevel@tonic-gate 		/* Treat eof as normal data */
83090Sstevel@tonic-gate 		if (sd_flags & STREOF)
83100Sstevel@tonic-gate 			retevents |= normevents;
83110Sstevel@tonic-gate 	}
83120Sstevel@tonic-gate 
83130Sstevel@tonic-gate 	*reventsp = (short)retevents;
83140Sstevel@tonic-gate 	if (retevents) {
83150Sstevel@tonic-gate 		if (headlocked)
83160Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
83170Sstevel@tonic-gate 		return (0);
83180Sstevel@tonic-gate 	}
83190Sstevel@tonic-gate 
83200Sstevel@tonic-gate 	/*
83210Sstevel@tonic-gate 	 * If poll() has not found any events yet, set up event cell
83220Sstevel@tonic-gate 	 * to wake up the poll if a requested event occurs on this
83230Sstevel@tonic-gate 	 * stream.  Check for collisions with outstanding poll requests.
83240Sstevel@tonic-gate 	 */
83250Sstevel@tonic-gate 	if (!anyyet) {
83260Sstevel@tonic-gate 		*phpp = &stp->sd_pollist;
83270Sstevel@tonic-gate 		if (headlocked == 0) {
83280Sstevel@tonic-gate 			polllock(&stp->sd_pollist, &stp->sd_lock);
83290Sstevel@tonic-gate 			headlocked = 1;
83300Sstevel@tonic-gate 		}
83310Sstevel@tonic-gate 		stp->sd_rput_opt |= SR_POLLIN;
83320Sstevel@tonic-gate 	}
83330Sstevel@tonic-gate 	if (headlocked)
83340Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
83350Sstevel@tonic-gate 	return (0);
83360Sstevel@tonic-gate }
83370Sstevel@tonic-gate 
83380Sstevel@tonic-gate /*
83390Sstevel@tonic-gate  * The purpose of putback() is to assure sleeping polls/reads
83400Sstevel@tonic-gate  * are awakened when there are no new messages arriving at the,
83410Sstevel@tonic-gate  * stream head, and a message is placed back on the read queue.
83420Sstevel@tonic-gate  *
83430Sstevel@tonic-gate  * sd_lock must be held when messages are placed back on stream
83440Sstevel@tonic-gate  * head.  (getq() holds sd_lock when it removes messages from
83450Sstevel@tonic-gate  * the queue)
83460Sstevel@tonic-gate  */
83470Sstevel@tonic-gate 
83480Sstevel@tonic-gate static void
putback(struct stdata * stp,queue_t * q,mblk_t * bp,int band)83490Sstevel@tonic-gate putback(struct stdata *stp, queue_t *q, mblk_t *bp, int band)
83500Sstevel@tonic-gate {
83516769Sja97890 	mblk_t	*qfirst;
83520Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&stp->sd_lock));
83534683Sja97890 
83546769Sja97890 	/*
83556769Sja97890 	 * As a result of lock-step ordering around q_lock and sd_lock,
83566769Sja97890 	 * it's possible for function calls like putnext() and
83576769Sja97890 	 * canputnext() to get an inaccurate picture of how much
83586769Sja97890 	 * data is really being processed at the stream head.
83596769Sja97890 	 * We only consolidate with existing messages on the queue
83606769Sja97890 	 * if the length of the message we want to put back is smaller
83616769Sja97890 	 * than the queue hiwater mark.
83626769Sja97890 	 */
83634683Sja97890 	if ((stp->sd_rput_opt & SR_CONSOL_DATA) &&
83646769Sja97890 	    (DB_TYPE(bp) == M_DATA) && ((qfirst = q->q_first) != NULL) &&
83656769Sja97890 	    (DB_TYPE(qfirst) == M_DATA) &&
83666769Sja97890 	    ((qfirst->b_flag & (MSGMARK|MSGDELIM)) == 0) &&
83676769Sja97890 	    ((bp->b_flag & (MSGMARK|MSGDELIM|MSGMARKNEXT)) == 0) &&
83686769Sja97890 	    (mp_cont_len(bp, NULL) < q->q_hiwat)) {
83694683Sja97890 		/*
83704683Sja97890 		 * We use the same logic as defined in strrput()
83714683Sja97890 		 * but in reverse as we are putting back onto the
83724683Sja97890 		 * queue and want to retain byte ordering.
83736769Sja97890 		 * Consolidate M_DATA messages with M_DATA ONLY.
83746769Sja97890 		 * strrput() allows the consolidation of M_DATA onto
83756769Sja97890 		 * M_PROTO | M_PCPROTO but not the other way round.
83766769Sja97890 		 *
83774683Sja97890 		 * The consolidation does not take place if the message
83784683Sja97890 		 * we are returning to the queue is marked with either
83794683Sja97890 		 * of the marks or the delim flag or if q_first
83804683Sja97890 		 * is marked with MSGMARK. The MSGMARK check is needed to
83814683Sja97890 		 * handle the odd semantics of MSGMARK where essentially
83824683Sja97890 		 * the whole message is to be treated as marked.
83834683Sja97890 		 * Carry any MSGMARKNEXT and MSGNOTMARKNEXT from q_first
83844683Sja97890 		 * to the front of the b_cont chain.
83854683Sja97890 		 */
83866769Sja97890 		rmvq_noenab(q, qfirst);
83876769Sja97890 
83886769Sja97890 		/*
83896769Sja97890 		 * The first message in the b_cont list
83906769Sja97890 		 * tracks MSGMARKNEXT and MSGNOTMARKNEXT.
83916769Sja97890 		 * We need to handle the case where we
83926769Sja97890 		 * are appending:
83936769Sja97890 		 *
83946769Sja97890 		 * 1) a MSGMARKNEXT to a MSGNOTMARKNEXT.
83956769Sja97890 		 * 2) a MSGMARKNEXT to a plain message.
83966769Sja97890 		 * 3) a MSGNOTMARKNEXT to a plain message
83976769Sja97890 		 * 4) a MSGNOTMARKNEXT to a MSGNOTMARKNEXT
83986769Sja97890 		 *    message.
83996769Sja97890 		 *
84006769Sja97890 		 * Thus we never append a MSGMARKNEXT or
84016769Sja97890 		 * MSGNOTMARKNEXT to a MSGMARKNEXT message.
84026769Sja97890 		 */
84036769Sja97890 		if (qfirst->b_flag & MSGMARKNEXT) {
84046769Sja97890 			bp->b_flag |= MSGMARKNEXT;
84056769Sja97890 			bp->b_flag &= ~MSGNOTMARKNEXT;
84066769Sja97890 			qfirst->b_flag &= ~MSGMARKNEXT;
84076769Sja97890 		} else if (qfirst->b_flag & MSGNOTMARKNEXT) {
84086769Sja97890 			bp->b_flag |= MSGNOTMARKNEXT;
84096769Sja97890 			qfirst->b_flag &= ~MSGNOTMARKNEXT;
84106769Sja97890 		}
84116769Sja97890 
84126769Sja97890 		linkb(bp, qfirst);
84134683Sja97890 	}
84140Sstevel@tonic-gate 	(void) putbq(q, bp);
84154683Sja97890 
84160Sstevel@tonic-gate 	/*
84170Sstevel@tonic-gate 	 * A message may have come in when the sd_lock was dropped in the
84180Sstevel@tonic-gate 	 * calling routine. If this is the case and STR*ATMARK info was
84190Sstevel@tonic-gate 	 * received, need to move that from the stream head to the q_last
84200Sstevel@tonic-gate 	 * so that SIOCATMARK can return the proper value.
84210Sstevel@tonic-gate 	 */
84220Sstevel@tonic-gate 	if (stp->sd_flag & (STRATMARK | STRNOTATMARK)) {
84230Sstevel@tonic-gate 		unsigned short *flagp = &q->q_last->b_flag;
84240Sstevel@tonic-gate 		uint_t b_flag = (uint_t)*flagp;
84250Sstevel@tonic-gate 
84260Sstevel@tonic-gate 		if (stp->sd_flag & STRATMARK) {
84270Sstevel@tonic-gate 			b_flag &= ~MSGNOTMARKNEXT;
84280Sstevel@tonic-gate 			b_flag |= MSGMARKNEXT;
84290Sstevel@tonic-gate 			stp->sd_flag &= ~STRATMARK;
84300Sstevel@tonic-gate 		} else {
84310Sstevel@tonic-gate 			b_flag &= ~MSGMARKNEXT;
84320Sstevel@tonic-gate 			b_flag |= MSGNOTMARKNEXT;
84330Sstevel@tonic-gate 			stp->sd_flag &= ~STRNOTATMARK;
84340Sstevel@tonic-gate 		}
84350Sstevel@tonic-gate 		*flagp = (unsigned short) b_flag;
84360Sstevel@tonic-gate 	}
84370Sstevel@tonic-gate 
84380Sstevel@tonic-gate #ifdef	DEBUG
84390Sstevel@tonic-gate 	/*
84400Sstevel@tonic-gate 	 * Make sure that the flags are not messed up.
84410Sstevel@tonic-gate 	 */
84420Sstevel@tonic-gate 	{
84430Sstevel@tonic-gate 		mblk_t *mp;
84440Sstevel@tonic-gate 		mp = q->q_last;
84450Sstevel@tonic-gate 		while (mp != NULL) {
84460Sstevel@tonic-gate 			ASSERT((mp->b_flag & (MSGMARKNEXT|MSGNOTMARKNEXT)) !=
84470Sstevel@tonic-gate 			    (MSGMARKNEXT|MSGNOTMARKNEXT));
84480Sstevel@tonic-gate 			mp = mp->b_cont;
84490Sstevel@tonic-gate 		}
84500Sstevel@tonic-gate 	}
84510Sstevel@tonic-gate #endif
84520Sstevel@tonic-gate 	if (q->q_first == bp) {
84530Sstevel@tonic-gate 		short pollevents;
84540Sstevel@tonic-gate 
84550Sstevel@tonic-gate 		if (stp->sd_flag & RSLEEP) {
84560Sstevel@tonic-gate 			stp->sd_flag &= ~RSLEEP;
84570Sstevel@tonic-gate 			cv_broadcast(&q->q_wait);
84580Sstevel@tonic-gate 		}
84590Sstevel@tonic-gate 		if (stp->sd_flag & STRPRI) {
84600Sstevel@tonic-gate 			pollevents = POLLPRI;
84610Sstevel@tonic-gate 		} else {
84620Sstevel@tonic-gate 			if (band == 0) {
84630Sstevel@tonic-gate 				if (!(stp->sd_rput_opt & SR_POLLIN))
84640Sstevel@tonic-gate 					return;
84650Sstevel@tonic-gate 				stp->sd_rput_opt &= ~SR_POLLIN;
84660Sstevel@tonic-gate 				pollevents = POLLIN | POLLRDNORM;
84670Sstevel@tonic-gate 			} else {
84680Sstevel@tonic-gate 				pollevents = POLLIN | POLLRDBAND;
84690Sstevel@tonic-gate 			}
84700Sstevel@tonic-gate 		}
84710Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
84720Sstevel@tonic-gate 		pollwakeup(&stp->sd_pollist, pollevents);
84730Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
84740Sstevel@tonic-gate 	}
84750Sstevel@tonic-gate }
84760Sstevel@tonic-gate 
84770Sstevel@tonic-gate /*
84780Sstevel@tonic-gate  * Return the held vnode attached to the stream head of a
84790Sstevel@tonic-gate  * given queue
84800Sstevel@tonic-gate  * It is the responsibility of the calling routine to ensure
84810Sstevel@tonic-gate  * that the queue does not go away (e.g. pop).
84820Sstevel@tonic-gate  */
84830Sstevel@tonic-gate vnode_t *
strq2vp(queue_t * qp)84840Sstevel@tonic-gate strq2vp(queue_t *qp)
84850Sstevel@tonic-gate {
84860Sstevel@tonic-gate 	vnode_t *vp;
84870Sstevel@tonic-gate 	vp = STREAM(qp)->sd_vnode;
84880Sstevel@tonic-gate 	ASSERT(vp != NULL);
84890Sstevel@tonic-gate 	VN_HOLD(vp);
84900Sstevel@tonic-gate 	return (vp);
84910Sstevel@tonic-gate }
84920Sstevel@tonic-gate 
84930Sstevel@tonic-gate /*
84940Sstevel@tonic-gate  * return the stream head write queue for the given vp
84950Sstevel@tonic-gate  * It is the responsibility of the calling routine to ensure
84960Sstevel@tonic-gate  * that the stream or vnode do not close.
84970Sstevel@tonic-gate  */
84980Sstevel@tonic-gate queue_t *
strvp2wq(vnode_t * vp)84990Sstevel@tonic-gate strvp2wq(vnode_t *vp)
85000Sstevel@tonic-gate {
85010Sstevel@tonic-gate 	ASSERT(vp->v_stream != NULL);
85020Sstevel@tonic-gate 	return (vp->v_stream->sd_wrq);
85030Sstevel@tonic-gate }
85040Sstevel@tonic-gate 
85050Sstevel@tonic-gate /*
85060Sstevel@tonic-gate  * pollwakeup stream head
85070Sstevel@tonic-gate  * It is the responsibility of the calling routine to ensure
85080Sstevel@tonic-gate  * that the stream or vnode do not close.
85090Sstevel@tonic-gate  */
85100Sstevel@tonic-gate void
strpollwakeup(vnode_t * vp,short event)85110Sstevel@tonic-gate strpollwakeup(vnode_t *vp, short event)
85120Sstevel@tonic-gate {
85130Sstevel@tonic-gate 	ASSERT(vp->v_stream);
85140Sstevel@tonic-gate 	pollwakeup(&vp->v_stream->sd_pollist, event);
85150Sstevel@tonic-gate }
85160Sstevel@tonic-gate 
85170Sstevel@tonic-gate /*
85180Sstevel@tonic-gate  * Mate the stream heads of two vnodes together. If the two vnodes are the
85190Sstevel@tonic-gate  * same, we just make the write-side point at the read-side -- otherwise,
85200Sstevel@tonic-gate  * we do a full mate.  Only works on vnodes associated with streams that are
85210Sstevel@tonic-gate  * still being built and thus have only a stream head.
85220Sstevel@tonic-gate  */
85230Sstevel@tonic-gate void
strmate(vnode_t * vp1,vnode_t * vp2)85240Sstevel@tonic-gate strmate(vnode_t *vp1, vnode_t *vp2)
85250Sstevel@tonic-gate {
85260Sstevel@tonic-gate 	queue_t *wrq1 = strvp2wq(vp1);
85270Sstevel@tonic-gate 	queue_t *wrq2 = strvp2wq(vp2);
85280Sstevel@tonic-gate 
85290Sstevel@tonic-gate 	/*
85300Sstevel@tonic-gate 	 * Verify that there are no modules on the stream yet.  We also
85310Sstevel@tonic-gate 	 * rely on the stream head always having a service procedure to
85320Sstevel@tonic-gate 	 * avoid tweaking q_nfsrv.
85330Sstevel@tonic-gate 	 */
85340Sstevel@tonic-gate 	ASSERT(wrq1->q_next == NULL && wrq2->q_next == NULL);
85350Sstevel@tonic-gate 	ASSERT(wrq1->q_qinfo->qi_srvp != NULL);
85360Sstevel@tonic-gate 	ASSERT(wrq2->q_qinfo->qi_srvp != NULL);
85370Sstevel@tonic-gate 
85380Sstevel@tonic-gate 	/*
85390Sstevel@tonic-gate 	 * If the queues are the same, just twist; otherwise do a full mate.
85400Sstevel@tonic-gate 	 */
85410Sstevel@tonic-gate 	if (wrq1 == wrq2) {
85420Sstevel@tonic-gate 		wrq1->q_next = _RD(wrq1);
85430Sstevel@tonic-gate 	} else {
85440Sstevel@tonic-gate 		wrq1->q_next = _RD(wrq2);
85450Sstevel@tonic-gate 		wrq2->q_next = _RD(wrq1);
85460Sstevel@tonic-gate 		STREAM(wrq1)->sd_mate = STREAM(wrq2);
85470Sstevel@tonic-gate 		STREAM(wrq1)->sd_flag |= STRMATE;
85480Sstevel@tonic-gate 		STREAM(wrq2)->sd_mate = STREAM(wrq1);
85490Sstevel@tonic-gate 		STREAM(wrq2)->sd_flag |= STRMATE;
85500Sstevel@tonic-gate 	}
85510Sstevel@tonic-gate }
85520Sstevel@tonic-gate 
85530Sstevel@tonic-gate /*
85540Sstevel@tonic-gate  * XXX will go away when console is correctly fixed.
85550Sstevel@tonic-gate  * Clean up the console PIDS, from previous I_SETSIG,
85560Sstevel@tonic-gate  * called only for cnopen which never calls strclean().
85570Sstevel@tonic-gate  */
85580Sstevel@tonic-gate void
str_cn_clean(struct vnode * vp)85590Sstevel@tonic-gate str_cn_clean(struct vnode *vp)
85600Sstevel@tonic-gate {
85610Sstevel@tonic-gate 	strsig_t *ssp, *pssp, *tssp;
85620Sstevel@tonic-gate 	struct stdata *stp;
85630Sstevel@tonic-gate 	struct pid  *pidp;
85640Sstevel@tonic-gate 	int update = 0;
85650Sstevel@tonic-gate 
85660Sstevel@tonic-gate 	ASSERT(vp->v_stream);
85670Sstevel@tonic-gate 	stp = vp->v_stream;
85680Sstevel@tonic-gate 	pssp = NULL;
85690Sstevel@tonic-gate 	mutex_enter(&stp->sd_lock);
85700Sstevel@tonic-gate 	ssp = stp->sd_siglist;
85710Sstevel@tonic-gate 	while (ssp) {
85720Sstevel@tonic-gate 		mutex_enter(&pidlock);
85730Sstevel@tonic-gate 		pidp = ssp->ss_pidp;
85740Sstevel@tonic-gate 		/*
85750Sstevel@tonic-gate 		 * Get rid of PID if the proc is gone.
85760Sstevel@tonic-gate 		 */
85770Sstevel@tonic-gate 		if (pidp->pid_prinactive) {
85780Sstevel@tonic-gate 			tssp = ssp->ss_next;
85790Sstevel@tonic-gate 			if (pssp)
85800Sstevel@tonic-gate 				pssp->ss_next = tssp;
85810Sstevel@tonic-gate 			else
85820Sstevel@tonic-gate 				stp->sd_siglist = tssp;
85830Sstevel@tonic-gate 			ASSERT(pidp->pid_ref <= 1);
85840Sstevel@tonic-gate 			PID_RELE(ssp->ss_pidp);
85850Sstevel@tonic-gate 			mutex_exit(&pidlock);
85860Sstevel@tonic-gate 			kmem_free(ssp, sizeof (strsig_t));
85870Sstevel@tonic-gate 			update = 1;
85880Sstevel@tonic-gate 			ssp = tssp;
85890Sstevel@tonic-gate 			continue;
85900Sstevel@tonic-gate 		} else
85910Sstevel@tonic-gate 			mutex_exit(&pidlock);
85920Sstevel@tonic-gate 		pssp = ssp;
85930Sstevel@tonic-gate 		ssp = ssp->ss_next;
85940Sstevel@tonic-gate 	}
85950Sstevel@tonic-gate 	if (update) {
85960Sstevel@tonic-gate 		stp->sd_sigflags = 0;
85970Sstevel@tonic-gate 		for (ssp = stp->sd_siglist; ssp; ssp = ssp->ss_next)
85980Sstevel@tonic-gate 			stp->sd_sigflags |= ssp->ss_events;
85990Sstevel@tonic-gate 	}
86000Sstevel@tonic-gate 	mutex_exit(&stp->sd_lock);
86010Sstevel@tonic-gate }
86020Sstevel@tonic-gate 
86030Sstevel@tonic-gate /*
86040Sstevel@tonic-gate  * Return B_TRUE if there is data in the message, B_FALSE otherwise.
86050Sstevel@tonic-gate  */
86060Sstevel@tonic-gate static boolean_t
msghasdata(mblk_t * bp)86070Sstevel@tonic-gate msghasdata(mblk_t *bp)
86080Sstevel@tonic-gate {
86090Sstevel@tonic-gate 	for (; bp; bp = bp->b_cont)
86100Sstevel@tonic-gate 		if (bp->b_datap->db_type == M_DATA) {
86110Sstevel@tonic-gate 			ASSERT(bp->b_wptr >= bp->b_rptr);
86120Sstevel@tonic-gate 			if (bp->b_wptr > bp->b_rptr)
86130Sstevel@tonic-gate 				return (B_TRUE);
86140Sstevel@tonic-gate 		}
86150Sstevel@tonic-gate 	return (B_FALSE);
86160Sstevel@tonic-gate }
8617