xref: /illumos-gate/usr/src/uts/common/io/rlmod.c (revision a8eee26a)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
237c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
2548bbca81SDaniel Hoffman  * Copyright (c) 2016 by Delphix. All rights reserved.
267c478bd9Sstevel@tonic-gate  */
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate /*
297c478bd9Sstevel@tonic-gate  * This module implements the services provided by the rlogin daemon
307c478bd9Sstevel@tonic-gate  * after the connection is set up.  Mainly this means responding to
317c478bd9Sstevel@tonic-gate  * interrupts and window size changes.  It begins operation in "disabled"
327c478bd9Sstevel@tonic-gate  * state, and sends a T_DATA_REQ to the daemon to indicate that it is
337c478bd9Sstevel@tonic-gate  * in place and ready to be enabled.  The daemon can then know when all
347c478bd9Sstevel@tonic-gate  * data which sneaked passed rlmod (before it was pushed) has been received.
357c478bd9Sstevel@tonic-gate  * The daemon may process this data, or send data back to be inserted in
367c478bd9Sstevel@tonic-gate  * the read queue at the head with the RL_IOC_ENABLE ioctl.
377c478bd9Sstevel@tonic-gate  */
387c478bd9Sstevel@tonic-gate 
397c478bd9Sstevel@tonic-gate #include <sys/types.h>
407c478bd9Sstevel@tonic-gate #include <sys/param.h>
417c478bd9Sstevel@tonic-gate #include <sys/stream.h>
427c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
437c478bd9Sstevel@tonic-gate #include <sys/strsun.h>
447c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
457c478bd9Sstevel@tonic-gate #include <sys/errno.h>
467c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
477c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
487c478bd9Sstevel@tonic-gate #include <sys/tihdr.h>
497c478bd9Sstevel@tonic-gate #include <sys/ptem.h>
507c478bd9Sstevel@tonic-gate #include <sys/conf.h>
517c478bd9Sstevel@tonic-gate #include <sys/debug.h>
527c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
537c478bd9Sstevel@tonic-gate #include <sys/vtrace.h>
547c478bd9Sstevel@tonic-gate #include <sys/rlioctl.h>
557c478bd9Sstevel@tonic-gate #include <sys/termios.h>
567c478bd9Sstevel@tonic-gate #include <sys/termio.h>
577c478bd9Sstevel@tonic-gate #include <sys/byteorder.h>
587c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
597c478bd9Sstevel@tonic-gate #include <sys/cryptmod.h>
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate extern struct streamtab rloginmodinfo;
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate static struct fmodsw fsw = {
647c478bd9Sstevel@tonic-gate 	"rlmod",
657c478bd9Sstevel@tonic-gate 	&rloginmodinfo,
667c478bd9Sstevel@tonic-gate 	D_MTQPAIR | D_MP
677c478bd9Sstevel@tonic-gate };
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate /*
707c478bd9Sstevel@tonic-gate  * Module linkage information for the kernel.
717c478bd9Sstevel@tonic-gate  */
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate static struct modlstrmod modlstrmod = {
747c478bd9Sstevel@tonic-gate 	&mod_strmodops,
757c478bd9Sstevel@tonic-gate 	"rloginmod module",
767c478bd9Sstevel@tonic-gate 	&fsw
777c478bd9Sstevel@tonic-gate };
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
807c478bd9Sstevel@tonic-gate 	MODREV_1, &modlstrmod, NULL
817c478bd9Sstevel@tonic-gate };
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate int
_init(void)857c478bd9Sstevel@tonic-gate _init(void)
867c478bd9Sstevel@tonic-gate {
877c478bd9Sstevel@tonic-gate 	return (mod_install(&modlinkage));
887c478bd9Sstevel@tonic-gate }
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate int
_fini(void)917c478bd9Sstevel@tonic-gate _fini(void)
927c478bd9Sstevel@tonic-gate {
937c478bd9Sstevel@tonic-gate 	return (mod_remove(&modlinkage));
947c478bd9Sstevel@tonic-gate }
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate int
_info(struct modinfo * modinfop)977c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
987c478bd9Sstevel@tonic-gate {
997c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
1007c478bd9Sstevel@tonic-gate }
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate struct rlmod_info; /* forward reference for function prototype */
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate static int		rlmodopen(queue_t *, dev_t *, int, int, cred_t *);
1057c478bd9Sstevel@tonic-gate static int		rlmodclose(queue_t *, int, cred_t *);
1067c478bd9Sstevel@tonic-gate static int		rlmodrput(queue_t *, mblk_t *);
1077c478bd9Sstevel@tonic-gate static int		rlmodrsrv(queue_t *);
1087c478bd9Sstevel@tonic-gate static int		rlmodwput(queue_t *, mblk_t *);
1097c478bd9Sstevel@tonic-gate static int		rlmodwsrv(queue_t *);
1107c478bd9Sstevel@tonic-gate static int		rlmodrmsg(queue_t *, mblk_t *);
1117c478bd9Sstevel@tonic-gate static mblk_t		*make_expmblk(char);
112*a8eee26aSToomas Soome static int		rlwinctl(queue_t *, mblk_t *);
1137c478bd9Sstevel@tonic-gate static mblk_t		*rlwinsetup(queue_t *, mblk_t *, unsigned char *);
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate static void		rlmod_timer(void *);
1167c478bd9Sstevel@tonic-gate static void		rlmod_buffer(void *);
1177c478bd9Sstevel@tonic-gate static boolean_t	tty_flow(queue_t *, struct rlmod_info *, mblk_t *);
1187c478bd9Sstevel@tonic-gate static boolean_t	rlmodwioctl(queue_t *, mblk_t *);
1197c478bd9Sstevel@tonic-gate static void		recover(queue_t *, mblk_t *, size_t);
1207c478bd9Sstevel@tonic-gate static void		recover1(queue_t *, size_t);
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate #define	RLMOD_ID	106
1237c478bd9Sstevel@tonic-gate #define	SIMWAIT		(1*hz)
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate /*
1267c478bd9Sstevel@tonic-gate  * Stream module data structure definitions.
1277c478bd9Sstevel@tonic-gate  * generally pushed onto tcp by rlogin daemon
1287c478bd9Sstevel@tonic-gate  *
1297c478bd9Sstevel@tonic-gate  */
1307c478bd9Sstevel@tonic-gate static	struct	module_info	rloginmodiinfo = {
1317c478bd9Sstevel@tonic-gate 	RLMOD_ID,				/* module id number */
1327c478bd9Sstevel@tonic-gate 	"rlmod",				/* module name */
1337c478bd9Sstevel@tonic-gate 	0,					/* minimum packet size */
1347c478bd9Sstevel@tonic-gate 	INFPSZ,					/* maximum packet size */
1357c478bd9Sstevel@tonic-gate 	512,					/* hi-water mark */
1367c478bd9Sstevel@tonic-gate 	256					/* lo-water mark */
1377c478bd9Sstevel@tonic-gate };
1387c478bd9Sstevel@tonic-gate 
1397c478bd9Sstevel@tonic-gate static	struct	qinit	rloginmodrinit = {
1407c478bd9Sstevel@tonic-gate 	rlmodrput,
1417c478bd9Sstevel@tonic-gate 	rlmodrsrv,
1427c478bd9Sstevel@tonic-gate 	rlmodopen,
1437c478bd9Sstevel@tonic-gate 	rlmodclose,
1447c478bd9Sstevel@tonic-gate 	nulldev,
1457c478bd9Sstevel@tonic-gate 	&rloginmodiinfo,
1467c478bd9Sstevel@tonic-gate 	NULL
1477c478bd9Sstevel@tonic-gate };
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate static	struct	qinit	rloginmodwinit = {
1507c478bd9Sstevel@tonic-gate 	rlmodwput,
1517c478bd9Sstevel@tonic-gate 	rlmodwsrv,
1527c478bd9Sstevel@tonic-gate 	NULL,
1537c478bd9Sstevel@tonic-gate 	NULL,
1547c478bd9Sstevel@tonic-gate 	nulldev,
1557c478bd9Sstevel@tonic-gate 	&rloginmodiinfo,
1567c478bd9Sstevel@tonic-gate 	NULL
1577c478bd9Sstevel@tonic-gate };
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate struct	streamtab	rloginmodinfo = {
1607c478bd9Sstevel@tonic-gate 	&rloginmodrinit,
1617c478bd9Sstevel@tonic-gate 	&rloginmodwinit,
1627c478bd9Sstevel@tonic-gate 	NULL,
1637c478bd9Sstevel@tonic-gate 	NULL
1647c478bd9Sstevel@tonic-gate };
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate /*
1677c478bd9Sstevel@tonic-gate  * Per-instance state struct for the rloginmod module.
1687c478bd9Sstevel@tonic-gate  */
1697c478bd9Sstevel@tonic-gate struct rlmod_info
1707c478bd9Sstevel@tonic-gate {
1717c478bd9Sstevel@tonic-gate 	int		flags;
1727c478bd9Sstevel@tonic-gate 	bufcall_id_t	wbufcid;
1737c478bd9Sstevel@tonic-gate 	bufcall_id_t	rbufcid;
1747c478bd9Sstevel@tonic-gate 	timeout_id_t	wtimoutid;
1757c478bd9Sstevel@tonic-gate 	timeout_id_t	rtimoutid;
1767c478bd9Sstevel@tonic-gate 	int		rl_expdat;
1777c478bd9Sstevel@tonic-gate 	int		stopmode;
1787c478bd9Sstevel@tonic-gate 	mblk_t		*unbind_mp;
1797c478bd9Sstevel@tonic-gate 	char		startc;
1807c478bd9Sstevel@tonic-gate 	char		stopc;
1817c478bd9Sstevel@tonic-gate 	char		oobdata[1];
1827c478bd9Sstevel@tonic-gate 	mblk_t		*wndw_sz_hd_mp;
1837c478bd9Sstevel@tonic-gate };
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate /*
1867c478bd9Sstevel@tonic-gate  * Flag used in flags
1877c478bd9Sstevel@tonic-gate  */
1887c478bd9Sstevel@tonic-gate #define	RL_DISABLED	0x1
1897c478bd9Sstevel@tonic-gate #define	RL_IOCPASSTHRU	0x2
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1927c478bd9Sstevel@tonic-gate static void
dummy_callback(void * arg)1937c478bd9Sstevel@tonic-gate dummy_callback(void *arg)
1947c478bd9Sstevel@tonic-gate {}
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate /*
1977c478bd9Sstevel@tonic-gate  * rlmodopen - open routine gets called when the
1987c478bd9Sstevel@tonic-gate  *	    module gets pushed onto the stream.
1997c478bd9Sstevel@tonic-gate  */
2007c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2017c478bd9Sstevel@tonic-gate static int
rlmodopen(queue_t * q,dev_t * devp,int oflag,int sflag,cred_t * cred)2027c478bd9Sstevel@tonic-gate rlmodopen(queue_t *q, dev_t *devp, int oflag, int sflag, cred_t *cred)
2037c478bd9Sstevel@tonic-gate {
2047c478bd9Sstevel@tonic-gate 	struct rlmod_info	*rmip;
2057c478bd9Sstevel@tonic-gate 	union T_primitives *tp;
2067c478bd9Sstevel@tonic-gate 	mblk_t *bp;
2077c478bd9Sstevel@tonic-gate 	int	error;
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate 	if (sflag != MODOPEN)
2107c478bd9Sstevel@tonic-gate 		return (EINVAL);
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate 	if (q->q_ptr != NULL) {
2137c478bd9Sstevel@tonic-gate 		/* It's already attached. */
2147c478bd9Sstevel@tonic-gate 		return (0);
2157c478bd9Sstevel@tonic-gate 	}
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate 	/*
2187c478bd9Sstevel@tonic-gate 	 * Allocate state structure.
2197c478bd9Sstevel@tonic-gate 	 */
2207c478bd9Sstevel@tonic-gate 	rmip = kmem_zalloc(sizeof (*rmip), KM_SLEEP);
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate 	/*
2237c478bd9Sstevel@tonic-gate 	 * Cross-link.
2247c478bd9Sstevel@tonic-gate 	 */
2257c478bd9Sstevel@tonic-gate 	q->q_ptr = rmip;
2267c478bd9Sstevel@tonic-gate 	WR(q)->q_ptr = rmip;
2277c478bd9Sstevel@tonic-gate 	rmip->rl_expdat = 0;
2287c478bd9Sstevel@tonic-gate 	rmip->stopmode = TIOCPKT_DOSTOP;
2297c478bd9Sstevel@tonic-gate 	rmip->startc = CTRL('q');
2307c478bd9Sstevel@tonic-gate 	rmip->stopc = CTRL('s');
2317c478bd9Sstevel@tonic-gate 	rmip->oobdata[0] = (char)TIOCPKT_WINDOW;
2327c478bd9Sstevel@tonic-gate 	rmip->wndw_sz_hd_mp = NULL;
2337c478bd9Sstevel@tonic-gate 	/*
2347c478bd9Sstevel@tonic-gate 	 * Allow only non-M_DATA blocks to pass up to in.rlogind until
2357c478bd9Sstevel@tonic-gate 	 * it is ready for M_DATA (indicated by RL_IOC_ENABLE).
2367c478bd9Sstevel@tonic-gate 	 */
2377c478bd9Sstevel@tonic-gate 	rmip->flags |= RL_DISABLED;
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate 	qprocson(q);
2407c478bd9Sstevel@tonic-gate 
2417c478bd9Sstevel@tonic-gate 	/*
2427c478bd9Sstevel@tonic-gate 	 * Since TCP operates in the TLI-inspired brain-dead fashion,
2437c478bd9Sstevel@tonic-gate 	 * the connection will revert to bound state if the connection
2447c478bd9Sstevel@tonic-gate 	 * is reset by the client.  We must send a T_UNBIND_REQ in
2457c478bd9Sstevel@tonic-gate 	 * that case so the port doesn't get "wedged" (preventing
2467c478bd9Sstevel@tonic-gate 	 * inetd from being able to restart the listener).  Allocate
2477c478bd9Sstevel@tonic-gate 	 * it here, so that we don't need to worry about allocb()
2487c478bd9Sstevel@tonic-gate 	 * failures later.
2497c478bd9Sstevel@tonic-gate 	 */
2507c478bd9Sstevel@tonic-gate 	while ((rmip->unbind_mp = allocb(sizeof (union T_primitives),
2517c478bd9Sstevel@tonic-gate 	    BPRI_HI)) == NULL) {
2527c478bd9Sstevel@tonic-gate 		bufcall_id_t id = qbufcall(q, sizeof (union T_primitives),
2537c478bd9Sstevel@tonic-gate 		    BPRI_HI, dummy_callback, NULL);
2547c478bd9Sstevel@tonic-gate 		if (!qwait_sig(q)) {
2557c478bd9Sstevel@tonic-gate 			qunbufcall(q, id);
2567c478bd9Sstevel@tonic-gate 			error = EINTR;
2577c478bd9Sstevel@tonic-gate 			goto fail;
2587c478bd9Sstevel@tonic-gate 		}
2597c478bd9Sstevel@tonic-gate 		qunbufcall(q, id);
2607c478bd9Sstevel@tonic-gate 	}
2617c478bd9Sstevel@tonic-gate 	rmip->unbind_mp->b_wptr = rmip->unbind_mp->b_rptr +
2627c478bd9Sstevel@tonic-gate 	    sizeof (struct T_unbind_req);
2637c478bd9Sstevel@tonic-gate 	rmip->unbind_mp->b_datap->db_type = M_PROTO;
2647c478bd9Sstevel@tonic-gate 	tp = (union T_primitives *)rmip->unbind_mp->b_rptr;
2657c478bd9Sstevel@tonic-gate 	tp->type = T_UNBIND_REQ;
2667c478bd9Sstevel@tonic-gate 
2677c478bd9Sstevel@tonic-gate 	/*
2687c478bd9Sstevel@tonic-gate 	 * Send a M_PROTO msg of type T_DATA_REQ (this is unique for
2697c478bd9Sstevel@tonic-gate 	 * read queue since only write queue can get T_DATA_REQ).
2707c478bd9Sstevel@tonic-gate 	 * Readstream routine in the daemon will do a getmsg() till
2717c478bd9Sstevel@tonic-gate 	 * it receives this proto message.
2727c478bd9Sstevel@tonic-gate 	 */
2737c478bd9Sstevel@tonic-gate 	while ((bp = allocb(sizeof (union T_primitives), BPRI_HI)) == NULL) {
2747c478bd9Sstevel@tonic-gate 		bufcall_id_t id = qbufcall(q, sizeof (union T_primitives),
2757c478bd9Sstevel@tonic-gate 		    BPRI_HI, dummy_callback, NULL);
2767c478bd9Sstevel@tonic-gate 		if (!qwait_sig(q)) {
2777c478bd9Sstevel@tonic-gate 			qunbufcall(q, id);
2787c478bd9Sstevel@tonic-gate 			error = EINTR;
2797c478bd9Sstevel@tonic-gate 			goto fail;
2807c478bd9Sstevel@tonic-gate 		}
2817c478bd9Sstevel@tonic-gate 		qunbufcall(q, id);
2827c478bd9Sstevel@tonic-gate 	}
2837c478bd9Sstevel@tonic-gate 	bp->b_datap->db_type = M_PROTO;
2847c478bd9Sstevel@tonic-gate 	bp->b_wptr = bp->b_rptr + sizeof (union T_primitives);
2857c478bd9Sstevel@tonic-gate 	tp = (union T_primitives *)bp->b_rptr;
2867c478bd9Sstevel@tonic-gate 	tp->type = T_DATA_REQ;
2877c478bd9Sstevel@tonic-gate 	tp->data_req.MORE_flag = 0;
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate 	putnext(q, bp);
2907c478bd9Sstevel@tonic-gate 	return (0);
2917c478bd9Sstevel@tonic-gate fail:
2927c478bd9Sstevel@tonic-gate 	qprocsoff(q);
2937c478bd9Sstevel@tonic-gate 	if (rmip->unbind_mp != NULL) {
2947c478bd9Sstevel@tonic-gate 		freemsg(rmip->unbind_mp);
2957c478bd9Sstevel@tonic-gate 	}
2967c478bd9Sstevel@tonic-gate 	kmem_free(rmip, sizeof (struct rlmod_info));
2977c478bd9Sstevel@tonic-gate 	q->q_ptr = NULL;
2987c478bd9Sstevel@tonic-gate 	WR(q)->q_ptr = NULL;
2997c478bd9Sstevel@tonic-gate 	return (error);
3007c478bd9Sstevel@tonic-gate }
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate /*
3047c478bd9Sstevel@tonic-gate  * rlmodclose - This routine gets called when the module
3057c478bd9Sstevel@tonic-gate  *	gets popped off of the stream.
3067c478bd9Sstevel@tonic-gate  */
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3097c478bd9Sstevel@tonic-gate static int
rlmodclose(queue_t * q,int flag,cred_t * credp)3107c478bd9Sstevel@tonic-gate rlmodclose(queue_t *q, int flag, cred_t *credp)
3117c478bd9Sstevel@tonic-gate {
3127c478bd9Sstevel@tonic-gate 	struct rlmod_info   *rmip = (struct rlmod_info *)q->q_ptr;
3137c478bd9Sstevel@tonic-gate 	mblk_t  *mp;
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 	/*
3167c478bd9Sstevel@tonic-gate 	 * Flush any write-side data downstream.  Ignoring flow
3177c478bd9Sstevel@tonic-gate 	 * control at this point is known to be safe because the
3187c478bd9Sstevel@tonic-gate 	 * M_HANGUP below poisons the stream such that no modules can
3197c478bd9Sstevel@tonic-gate 	 * be pushed again.
3207c478bd9Sstevel@tonic-gate 	 */
3217c478bd9Sstevel@tonic-gate 	while (mp = getq(WR(q)))
3227c478bd9Sstevel@tonic-gate 		putnext(WR(q), mp);
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate 	/* Poison the stream head so that we can't be pushed again. */
3257c478bd9Sstevel@tonic-gate 	(void) putnextctl(q, M_HANGUP);
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate 	qprocsoff(q);
3287c478bd9Sstevel@tonic-gate 	if (rmip->wbufcid) {
3297c478bd9Sstevel@tonic-gate 		qunbufcall(q, rmip->wbufcid);
3307c478bd9Sstevel@tonic-gate 		rmip->wbufcid = 0;
3317c478bd9Sstevel@tonic-gate 	}
3327c478bd9Sstevel@tonic-gate 	if (rmip->rbufcid) {
3337c478bd9Sstevel@tonic-gate 		qunbufcall(q, rmip->rbufcid);
3347c478bd9Sstevel@tonic-gate 		rmip->rbufcid = 0;
3357c478bd9Sstevel@tonic-gate 	}
3367c478bd9Sstevel@tonic-gate 	if (rmip->wtimoutid) {
3377c478bd9Sstevel@tonic-gate 		(void) quntimeout(q, rmip->wtimoutid);
3387c478bd9Sstevel@tonic-gate 		rmip->wtimoutid = 0;
3397c478bd9Sstevel@tonic-gate 	}
3407c478bd9Sstevel@tonic-gate 	if (rmip->rtimoutid) {
3417c478bd9Sstevel@tonic-gate 		(void) quntimeout(q, rmip->rtimoutid);
3427c478bd9Sstevel@tonic-gate 		rmip->rtimoutid = 0;
3437c478bd9Sstevel@tonic-gate 	}
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate 	if (rmip->unbind_mp != NULL) {
3467c478bd9Sstevel@tonic-gate 		freemsg(rmip->unbind_mp);
3477c478bd9Sstevel@tonic-gate 	}
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate 	if (rmip->wndw_sz_hd_mp != NULL) {
3507c478bd9Sstevel@tonic-gate 		freemsg(rmip->wndw_sz_hd_mp);
3517c478bd9Sstevel@tonic-gate 	}
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate 	kmem_free(q->q_ptr, sizeof (struct rlmod_info));
3547c478bd9Sstevel@tonic-gate 	q->q_ptr = WR(q)->q_ptr = NULL;
3557c478bd9Sstevel@tonic-gate 	return (0);
3567c478bd9Sstevel@tonic-gate }
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate /*
3597c478bd9Sstevel@tonic-gate  * rlmodrput - Module read queue put procedure.
3607c478bd9Sstevel@tonic-gate  *	This is called from the module or
3617c478bd9Sstevel@tonic-gate  *	driver downstream.
3627c478bd9Sstevel@tonic-gate  */
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate static int
rlmodrput(queue_t * q,mblk_t * mp)3657c478bd9Sstevel@tonic-gate rlmodrput(queue_t *q, mblk_t *mp)
3667c478bd9Sstevel@tonic-gate {
3677c478bd9Sstevel@tonic-gate 	struct rlmod_info    *rmip = (struct rlmod_info *)q->q_ptr;
3687c478bd9Sstevel@tonic-gate 	union T_primitives *tip;
3697c478bd9Sstevel@tonic-gate 
3707c478bd9Sstevel@tonic-gate 	TRACE_2(TR_FAC_RLOGINP, TR_RLOGINP_RPUT_IN, "rlmodrput start: "
3717c478bd9Sstevel@tonic-gate 	    "q %p, mp %p", q, mp);
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate 	/* if low (normal) priority... */
3757c478bd9Sstevel@tonic-gate 	if ((mp->b_datap->db_type < QPCTL) &&
3767c478bd9Sstevel@tonic-gate 	    /* ...and data is already queued... */
3777c478bd9Sstevel@tonic-gate 	    ((q->q_first) ||
378*a8eee26aSToomas Soome 	    /* ...or currently disabled and this is M_DATA... */
379*a8eee26aSToomas Soome 	    ((rmip->flags & RL_DISABLED) &&
380*a8eee26aSToomas Soome 	    (mp->b_datap->db_type == M_DATA)))) {
3817c478bd9Sstevel@tonic-gate 		/* ...delay delivery of the message */
3827c478bd9Sstevel@tonic-gate 		(void) putq(q, mp);
3837c478bd9Sstevel@tonic-gate 		TRACE_3(TR_FAC_RLOGINP, TR_RLOGINP_RPUT_OUT,
3847c478bd9Sstevel@tonic-gate 		    "rlmodrput end: q %p, mp %p, %s", q, mp, "flow");
3857c478bd9Sstevel@tonic-gate 		return (0);
3867c478bd9Sstevel@tonic-gate 	}
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
3897c478bd9Sstevel@tonic-gate 
3907c478bd9Sstevel@tonic-gate 	case M_PROTO:
3917c478bd9Sstevel@tonic-gate 	case M_PCPROTO:
3927c478bd9Sstevel@tonic-gate 		tip = (union T_primitives *)mp->b_rptr;
3937c478bd9Sstevel@tonic-gate 		switch (tip->type) {
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate 		case T_ORDREL_IND:
3967c478bd9Sstevel@tonic-gate 		case T_DISCON_IND:
3977c478bd9Sstevel@tonic-gate 			/* Make into M_HANGUP and putnext */
3987c478bd9Sstevel@tonic-gate 			mp->b_datap->db_type = M_HANGUP;
3997c478bd9Sstevel@tonic-gate 			mp->b_wptr = mp->b_rptr;
4007c478bd9Sstevel@tonic-gate 			if (mp->b_cont) {
4017c478bd9Sstevel@tonic-gate 				freemsg(mp->b_cont);
4027c478bd9Sstevel@tonic-gate 				mp->b_cont = NULL;
4037c478bd9Sstevel@tonic-gate 			}
4047c478bd9Sstevel@tonic-gate 			/*
4057c478bd9Sstevel@tonic-gate 			 * If we haven't already, send T_UNBIND_REQ to prevent
4067c478bd9Sstevel@tonic-gate 			 * TCP from going into "BOUND" state and locking up the
4077c478bd9Sstevel@tonic-gate 			 * port.
4087c478bd9Sstevel@tonic-gate 			 */
4097c478bd9Sstevel@tonic-gate 			if (tip->type == T_DISCON_IND && rmip->unbind_mp !=
4107c478bd9Sstevel@tonic-gate 			    NULL) {
4117c478bd9Sstevel@tonic-gate 				putnext(q, mp);
4127c478bd9Sstevel@tonic-gate 				qreply(q, rmip->unbind_mp);
4137c478bd9Sstevel@tonic-gate 				rmip->unbind_mp = NULL;
4147c478bd9Sstevel@tonic-gate 			} else {
4157c478bd9Sstevel@tonic-gate 				putnext(q, mp);
4167c478bd9Sstevel@tonic-gate 			}
4177c478bd9Sstevel@tonic-gate 			break;
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate 		/*
4207c478bd9Sstevel@tonic-gate 		 * We only get T_OK_ACK when we issue the unbind, and it can
4217c478bd9Sstevel@tonic-gate 		 * be ignored safely.
4227c478bd9Sstevel@tonic-gate 		 */
4237c478bd9Sstevel@tonic-gate 		case T_OK_ACK:
4247c478bd9Sstevel@tonic-gate 			ASSERT(rmip->unbind_mp == NULL);
4257c478bd9Sstevel@tonic-gate 			freemsg(mp);
4267c478bd9Sstevel@tonic-gate 			break;
4277c478bd9Sstevel@tonic-gate 
4287c478bd9Sstevel@tonic-gate 		default:
4297c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE,
4307c478bd9Sstevel@tonic-gate 			    "rlmodrput: got 0x%x type M_PROTO/M_PCPROTO msg",
4317c478bd9Sstevel@tonic-gate 			    tip->type);
4327c478bd9Sstevel@tonic-gate 			freemsg(mp);
4337c478bd9Sstevel@tonic-gate 		}
4347c478bd9Sstevel@tonic-gate 		break;
4357c478bd9Sstevel@tonic-gate 
4367c478bd9Sstevel@tonic-gate 	case M_DATA:
4377c478bd9Sstevel@tonic-gate 		if (canputnext(q) && q->q_first == NULL) {
4387c478bd9Sstevel@tonic-gate 			(void) rlmodrmsg(q, mp);
4397c478bd9Sstevel@tonic-gate 		} else {
4407c478bd9Sstevel@tonic-gate 			(void) putq(q, mp);
4417c478bd9Sstevel@tonic-gate 		}
4427c478bd9Sstevel@tonic-gate 		break;
4437c478bd9Sstevel@tonic-gate 
4447c478bd9Sstevel@tonic-gate 	case M_FLUSH:
4457c478bd9Sstevel@tonic-gate 		/*
4467c478bd9Sstevel@tonic-gate 		 * Since M_FLUSH came from TCP, we mark it bound for
4477c478bd9Sstevel@tonic-gate 		 * daemon, not tty.  This only happens when TCP expects
4487c478bd9Sstevel@tonic-gate 		 * to do a connection reset.
4497c478bd9Sstevel@tonic-gate 		 */
4507c478bd9Sstevel@tonic-gate 		mp->b_flag |= MSGMARK;
4517c478bd9Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHR)
4527c478bd9Sstevel@tonic-gate 			flushq(q, FLUSHALL);
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate 		putnext(q, mp);
4557c478bd9Sstevel@tonic-gate 		break;
4567c478bd9Sstevel@tonic-gate 
4577c478bd9Sstevel@tonic-gate 	case M_PCSIG:
4587c478bd9Sstevel@tonic-gate 	case M_ERROR:
4597c478bd9Sstevel@tonic-gate 	case M_IOCACK:
4607c478bd9Sstevel@tonic-gate 	case M_IOCNAK:
4617c478bd9Sstevel@tonic-gate 	case M_SETOPTS:
4627c478bd9Sstevel@tonic-gate 		if (mp->b_datap->db_type <= QPCTL && !canputnext(q))
4637c478bd9Sstevel@tonic-gate 			(void) putq(q, mp);
4647c478bd9Sstevel@tonic-gate 		else
4657c478bd9Sstevel@tonic-gate 			putnext(q, mp);
4667c478bd9Sstevel@tonic-gate 		break;
4677c478bd9Sstevel@tonic-gate 
4687c478bd9Sstevel@tonic-gate 	default:
4697c478bd9Sstevel@tonic-gate #ifdef DEBUG
4707c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "rlmodrput: unexpected msg type 0x%x",
4717c478bd9Sstevel@tonic-gate 		    mp->b_datap->db_type);
4727c478bd9Sstevel@tonic-gate #endif
4737c478bd9Sstevel@tonic-gate 		freemsg(mp);
4747c478bd9Sstevel@tonic-gate 	}
4757c478bd9Sstevel@tonic-gate 	TRACE_3(TR_FAC_RLOGINP, TR_RLOGINP_RPUT_OUT, "rlmodrput end: q %p, "
476*a8eee26aSToomas Soome 	    "mp %p, %s", q, mp, "done");
4777c478bd9Sstevel@tonic-gate 	return (0);
4787c478bd9Sstevel@tonic-gate }
4797c478bd9Sstevel@tonic-gate 
4807c478bd9Sstevel@tonic-gate /*
4817c478bd9Sstevel@tonic-gate  * rlmodrsrv - module read service procedure
4827c478bd9Sstevel@tonic-gate  */
4837c478bd9Sstevel@tonic-gate static int
rlmodrsrv(queue_t * q)4847c478bd9Sstevel@tonic-gate rlmodrsrv(queue_t *q)
4857c478bd9Sstevel@tonic-gate {
4867c478bd9Sstevel@tonic-gate 	mblk_t	*mp;
4877c478bd9Sstevel@tonic-gate 	struct rlmod_info    *rmip = (struct rlmod_info *)q->q_ptr;
4887c478bd9Sstevel@tonic-gate 	union T_primitives *tip;
4897c478bd9Sstevel@tonic-gate 
4907c478bd9Sstevel@tonic-gate 	TRACE_1(TR_FAC_RLOGINP, TR_RLOGINP_RSRV_IN, "rlmodrsrv start: "
4917c478bd9Sstevel@tonic-gate 	    "q %p", q);
4927c478bd9Sstevel@tonic-gate 	while ((mp = getq(q)) != NULL) {
4937c478bd9Sstevel@tonic-gate 
4947c478bd9Sstevel@tonic-gate 		switch (mp->b_datap->db_type) {
4957c478bd9Sstevel@tonic-gate 		case M_DATA:
4967c478bd9Sstevel@tonic-gate 			if (rmip->flags & RL_DISABLED) {
4977c478bd9Sstevel@tonic-gate 				(void) putbq(q, mp);
4987c478bd9Sstevel@tonic-gate 				TRACE_3(TR_FAC_RLOGINP, TR_RLOGINP_RSRV_OUT,
499*a8eee26aSToomas Soome 				    "rlmodrsrv end: q %p, mp %p, %s", q, mp,
500*a8eee26aSToomas Soome 				    "disabled");
5017c478bd9Sstevel@tonic-gate 				return (0);
5027c478bd9Sstevel@tonic-gate 			}
5037c478bd9Sstevel@tonic-gate 			if (!canputnext(q)) {
5047c478bd9Sstevel@tonic-gate 				(void) putbq(q, mp);
5057c478bd9Sstevel@tonic-gate 				TRACE_3(TR_FAC_RLOGINP, TR_RLOGINP_RSRV_OUT,
5067c478bd9Sstevel@tonic-gate 				    "rlmodrsrv end: q %p, mp %p, %s",
5077c478bd9Sstevel@tonic-gate 				    q, mp, "!canputnext");
5087c478bd9Sstevel@tonic-gate 				return (0);
5097c478bd9Sstevel@tonic-gate 			}
5107c478bd9Sstevel@tonic-gate 			if (!rlmodrmsg(q, mp)) {
5117c478bd9Sstevel@tonic-gate 				TRACE_3(TR_FAC_RLOGINP, TR_RLOGINP_RSRV_OUT,
5127c478bd9Sstevel@tonic-gate 				    "rlmodrsrv end: q %p, mp %p, %s",
5137c478bd9Sstevel@tonic-gate 				    q, mp, "!rlmodrmsg");
5147c478bd9Sstevel@tonic-gate 				return (0);
5157c478bd9Sstevel@tonic-gate 			}
5167c478bd9Sstevel@tonic-gate 			break;
5177c478bd9Sstevel@tonic-gate 
5187c478bd9Sstevel@tonic-gate 		case M_PROTO:
5197c478bd9Sstevel@tonic-gate 			tip = (union T_primitives *)mp->b_rptr;
5207c478bd9Sstevel@tonic-gate 			switch (tip->type) {
5217c478bd9Sstevel@tonic-gate 
5227c478bd9Sstevel@tonic-gate 			case T_ORDREL_IND:
5237c478bd9Sstevel@tonic-gate 			case T_DISCON_IND:
5247c478bd9Sstevel@tonic-gate 				/* Make into M_HANGUP and putnext */
5257c478bd9Sstevel@tonic-gate 				mp->b_datap->db_type = M_HANGUP;
5267c478bd9Sstevel@tonic-gate 				mp->b_wptr = mp->b_rptr;
5277c478bd9Sstevel@tonic-gate 				if (mp->b_cont) {
5287c478bd9Sstevel@tonic-gate 					freemsg(mp->b_cont);
5297c478bd9Sstevel@tonic-gate 					mp->b_cont = NULL;
5307c478bd9Sstevel@tonic-gate 				}
5317c478bd9Sstevel@tonic-gate 				/*
5327c478bd9Sstevel@tonic-gate 				 * If we haven't already, send T_UNBIND_REQ
5337c478bd9Sstevel@tonic-gate 				 * to prevent TCP from going into "BOUND"
5347c478bd9Sstevel@tonic-gate 				 * state and locking up the port.
5357c478bd9Sstevel@tonic-gate 				 */
5367c478bd9Sstevel@tonic-gate 				if (tip->type == T_DISCON_IND &&
5377c478bd9Sstevel@tonic-gate 				    rmip->unbind_mp != NULL) {
5387c478bd9Sstevel@tonic-gate 					putnext(q, mp);
5397c478bd9Sstevel@tonic-gate 					qreply(q, rmip->unbind_mp);
5407c478bd9Sstevel@tonic-gate 					rmip->unbind_mp = NULL;
5417c478bd9Sstevel@tonic-gate 				} else {
5427c478bd9Sstevel@tonic-gate 					putnext(q, mp);
5437c478bd9Sstevel@tonic-gate 				}
5447c478bd9Sstevel@tonic-gate 				break;
5457c478bd9Sstevel@tonic-gate 
5467c478bd9Sstevel@tonic-gate 			/*
5477c478bd9Sstevel@tonic-gate 			 * We only get T_OK_ACK when we issue the unbind, and
5487c478bd9Sstevel@tonic-gate 			 * it can be ignored safely.
5497c478bd9Sstevel@tonic-gate 			 */
5507c478bd9Sstevel@tonic-gate 			case T_OK_ACK:
5517c478bd9Sstevel@tonic-gate 				ASSERT(rmip->unbind_mp == NULL);
5527c478bd9Sstevel@tonic-gate 				freemsg(mp);
5537c478bd9Sstevel@tonic-gate 				break;
5547c478bd9Sstevel@tonic-gate 
5557c478bd9Sstevel@tonic-gate 			default:
5567c478bd9Sstevel@tonic-gate 				cmn_err(CE_NOTE,
5577c478bd9Sstevel@tonic-gate 				    "rlmodrsrv: got 0x%x type PROTO msg",
5587c478bd9Sstevel@tonic-gate 				    tip->type);
5597c478bd9Sstevel@tonic-gate 				freemsg(mp);
5607c478bd9Sstevel@tonic-gate 			}
5617c478bd9Sstevel@tonic-gate 			break;
5627c478bd9Sstevel@tonic-gate 
5637c478bd9Sstevel@tonic-gate 		case M_SETOPTS:
5647c478bd9Sstevel@tonic-gate 			if (!canputnext(q)) {
5657c478bd9Sstevel@tonic-gate 				(void) putbq(q, mp);
5667c478bd9Sstevel@tonic-gate 				TRACE_3(TR_FAC_RLOGINP, TR_RLOGINP_RSRV_OUT,
5677c478bd9Sstevel@tonic-gate 				    "rlmodrsrv end: q %p, mp %p, %s",
5687c478bd9Sstevel@tonic-gate 				    q, mp, "!canputnext M_SETOPTS");
5697c478bd9Sstevel@tonic-gate 				return (0);
5707c478bd9Sstevel@tonic-gate 			}
5717c478bd9Sstevel@tonic-gate 			putnext(q, mp);
5727c478bd9Sstevel@tonic-gate 			break;
5737c478bd9Sstevel@tonic-gate 
5747c478bd9Sstevel@tonic-gate 		default:
5757c478bd9Sstevel@tonic-gate #ifdef DEBUG
5767c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE,
5777c478bd9Sstevel@tonic-gate 			    "rlmodrsrv: unexpected msg type 0x%x",
5787c478bd9Sstevel@tonic-gate 			    mp->b_datap->db_type);
5797c478bd9Sstevel@tonic-gate #endif
5807c478bd9Sstevel@tonic-gate 			freemsg(mp);
5817c478bd9Sstevel@tonic-gate 		}
5827c478bd9Sstevel@tonic-gate 	}
5837c478bd9Sstevel@tonic-gate 
5847c478bd9Sstevel@tonic-gate 	TRACE_3(TR_FAC_RLOGINP, TR_RLOGINP_RSRV_OUT, "rlmodrsrv end: q %p, "
5857c478bd9Sstevel@tonic-gate 	    "mp %p, %s", q, mp, "empty");
5867c478bd9Sstevel@tonic-gate 
5877c478bd9Sstevel@tonic-gate 	return (0);
5887c478bd9Sstevel@tonic-gate }
5897c478bd9Sstevel@tonic-gate 
5907c478bd9Sstevel@tonic-gate /*
5917c478bd9Sstevel@tonic-gate  * rlmodwput - Module write queue put procedure.
5927c478bd9Sstevel@tonic-gate  *	All non-zero messages are send downstream unchanged
5937c478bd9Sstevel@tonic-gate  */
5947c478bd9Sstevel@tonic-gate static int
rlmodwput(queue_t * q,mblk_t * mp)5957c478bd9Sstevel@tonic-gate rlmodwput(queue_t *q, mblk_t *mp)
5967c478bd9Sstevel@tonic-gate {
5977c478bd9Sstevel@tonic-gate 	char cntl;
5987c478bd9Sstevel@tonic-gate 	struct rlmod_info *rmip = (struct rlmod_info *)q->q_ptr;
5997c478bd9Sstevel@tonic-gate 	mblk_t *tmpmp;
6007c478bd9Sstevel@tonic-gate 	int rw;
6017c478bd9Sstevel@tonic-gate 
6027c478bd9Sstevel@tonic-gate 	TRACE_2(TR_FAC_RLOGINP, TR_RLOGINP_WPUT_IN, "rlmodwput start: "
6037c478bd9Sstevel@tonic-gate 	    "q %p, mp %p", q, mp);
6047c478bd9Sstevel@tonic-gate 
6057c478bd9Sstevel@tonic-gate 	if (rmip->rl_expdat) {
6067c478bd9Sstevel@tonic-gate 		/*
6077c478bd9Sstevel@tonic-gate 		 * call make_expmblk to create an expedited
6087c478bd9Sstevel@tonic-gate 		 * message block.
6097c478bd9Sstevel@tonic-gate 		 */
6107c478bd9Sstevel@tonic-gate 		cntl = rmip->oobdata[0] | TIOCPKT_FLUSHWRITE;
6117c478bd9Sstevel@tonic-gate 
6127c478bd9Sstevel@tonic-gate 		if (!canputnext(q)) {
6137c478bd9Sstevel@tonic-gate 			(void) putq(q, mp);
6147c478bd9Sstevel@tonic-gate 			TRACE_3(TR_FAC_RLOGINP, TR_RLOGINP_WPUT_OUT,
6157c478bd9Sstevel@tonic-gate 			    "rlmodwput end: q %p, mp %p, %s",
6167c478bd9Sstevel@tonic-gate 			    q, mp, "expdata && !canputnext");
6177c478bd9Sstevel@tonic-gate 			return (0);
6187c478bd9Sstevel@tonic-gate 		}
6197c478bd9Sstevel@tonic-gate 		if ((tmpmp = make_expmblk(cntl))) {
6207c478bd9Sstevel@tonic-gate 			putnext(q, tmpmp);
6217c478bd9Sstevel@tonic-gate 			rmip->rl_expdat = 0;
6227c478bd9Sstevel@tonic-gate 		} else {
6237c478bd9Sstevel@tonic-gate 			recover1(q, sizeof (mblk_t)); /* XXX.sparker */
6247c478bd9Sstevel@tonic-gate 		}
6257c478bd9Sstevel@tonic-gate 	}
6267c478bd9Sstevel@tonic-gate 
6277c478bd9Sstevel@tonic-gate 	if ((q->q_first || rmip->rl_expdat) && mp->b_datap->db_type < QPCTL) {
6287c478bd9Sstevel@tonic-gate 		(void) putq(q, mp);
6297c478bd9Sstevel@tonic-gate 		TRACE_3(TR_FAC_RLOGINP, TR_RLOGINP_WPUT_OUT, "rlmodwput end: "
6307c478bd9Sstevel@tonic-gate 		    "q %p, mp %p, %s", q, mp, "queued data");
6317c478bd9Sstevel@tonic-gate 		return (0);
6327c478bd9Sstevel@tonic-gate 	}
6337c478bd9Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
6347c478bd9Sstevel@tonic-gate 
6357c478bd9Sstevel@tonic-gate 	case M_DATA:
6367c478bd9Sstevel@tonic-gate 		if (!canputnext(q))
6377c478bd9Sstevel@tonic-gate 			(void) putq(q, mp);
6387c478bd9Sstevel@tonic-gate 		else
6397c478bd9Sstevel@tonic-gate 			putnext(q, mp);
6407c478bd9Sstevel@tonic-gate 		break;
6417c478bd9Sstevel@tonic-gate 
6427c478bd9Sstevel@tonic-gate 	case M_FLUSH:
6437c478bd9Sstevel@tonic-gate 		/*
6447c478bd9Sstevel@tonic-gate 		 * We must take care to create and forward out-of-band data
6457c478bd9Sstevel@tonic-gate 		 * indicating the flush to the far side.
6467c478bd9Sstevel@tonic-gate 		 */
6477c478bd9Sstevel@tonic-gate 		rw = *mp->b_rptr;
6487c478bd9Sstevel@tonic-gate 		*mp->b_rptr &= ~FLUSHW;
6497c478bd9Sstevel@tonic-gate 		qreply(q, mp);
6507c478bd9Sstevel@tonic-gate 		if (rw & FLUSHW) {
6517c478bd9Sstevel@tonic-gate 			/*
6527c478bd9Sstevel@tonic-gate 			 * Since all rlogin protocol data is sent in this
6537c478bd9Sstevel@tonic-gate 			 * direction as urgent data, and TCP does not flush
6547c478bd9Sstevel@tonic-gate 			 * urgent data, it is okay to actually forward this
6557c478bd9Sstevel@tonic-gate 			 * flush.  (telmod cannot.)
6567c478bd9Sstevel@tonic-gate 			 */
6577c478bd9Sstevel@tonic-gate 			flushq(q, FLUSHDATA);
6587c478bd9Sstevel@tonic-gate 			/*
6597c478bd9Sstevel@tonic-gate 			 * The putnextctl1() call can only fail if we're
6607c478bd9Sstevel@tonic-gate 			 * out of memory.  Ideally, we might set a state
6617c478bd9Sstevel@tonic-gate 			 * bit and reschedule ourselves when memory
6627c478bd9Sstevel@tonic-gate 			 * becomes available, so we make sure not to miss
6637c478bd9Sstevel@tonic-gate 			 * sending the FLUSHW to TCP before the urgent
6647c478bd9Sstevel@tonic-gate 			 * byte.  Not doing this just means in some cases
6657c478bd9Sstevel@tonic-gate 			 * a bit more trash passes before the flush takes
6667c478bd9Sstevel@tonic-gate 			 * hold.
6677c478bd9Sstevel@tonic-gate 			 */
6687c478bd9Sstevel@tonic-gate 			(void) putnextctl1(q, M_FLUSH, FLUSHW);
6697c478bd9Sstevel@tonic-gate 			/*
6707c478bd9Sstevel@tonic-gate 			 * Notify peer of the write flush request.
6717c478bd9Sstevel@tonic-gate 			 */
6727c478bd9Sstevel@tonic-gate 			cntl = rmip->oobdata[0] | TIOCPKT_FLUSHWRITE;
6737c478bd9Sstevel@tonic-gate 			if (!canputnext(q)) {
6747c478bd9Sstevel@tonic-gate 				TRACE_3(TR_FAC_RLOGINP, TR_RLOGINP_WPUT_OUT,
6757c478bd9Sstevel@tonic-gate 				    "rlmodwput end: q %p, mp %p, %s",
6767c478bd9Sstevel@tonic-gate 				    q, mp, "flushw && !canputnext");
6777c478bd9Sstevel@tonic-gate 				return (0);
6787c478bd9Sstevel@tonic-gate 			}
6797c478bd9Sstevel@tonic-gate 			if ((mp = make_expmblk(cntl)) == NULL) {
6807c478bd9Sstevel@tonic-gate 				rmip->rl_expdat = 1;
6817c478bd9Sstevel@tonic-gate 				recover1(q, sizeof (mblk_t));
6827c478bd9Sstevel@tonic-gate 				TRACE_3(TR_FAC_RLOGINP, TR_RLOGINP_WPUT_OUT,
6837c478bd9Sstevel@tonic-gate 				    "rlmodwput end: q %p, mp %p, %s",
6847c478bd9Sstevel@tonic-gate 				    q, mp, "!make_expmblk");
6857c478bd9Sstevel@tonic-gate 				return (0);
6867c478bd9Sstevel@tonic-gate 			}
6877c478bd9Sstevel@tonic-gate 			putnext(q, mp);
6887c478bd9Sstevel@tonic-gate 		}
6897c478bd9Sstevel@tonic-gate 		break;
6907c478bd9Sstevel@tonic-gate 
6917c478bd9Sstevel@tonic-gate 	case M_IOCTL:
6927c478bd9Sstevel@tonic-gate 		if (!rlmodwioctl(q, mp))
6937c478bd9Sstevel@tonic-gate 			(void) putq(q, mp);
6947c478bd9Sstevel@tonic-gate 		break;
6957c478bd9Sstevel@tonic-gate 
6967c478bd9Sstevel@tonic-gate 	case M_PROTO:
6977c478bd9Sstevel@tonic-gate 		switch (((union T_primitives *)mp->b_rptr)->type) {
6987c478bd9Sstevel@tonic-gate 		case T_EXDATA_REQ:
6997c478bd9Sstevel@tonic-gate 		case T_ORDREL_REQ:
7007c478bd9Sstevel@tonic-gate 		case T_DISCON_REQ:
7017c478bd9Sstevel@tonic-gate 			putnext(q, mp);
7027c478bd9Sstevel@tonic-gate 			break;
7037c478bd9Sstevel@tonic-gate 
7047c478bd9Sstevel@tonic-gate 		default:
7057c478bd9Sstevel@tonic-gate #ifdef DEBUG
7067c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE,
7077c478bd9Sstevel@tonic-gate 			    "rlmodwput: unexpected TPI primitive 0x%x",
7087c478bd9Sstevel@tonic-gate 			    ((union T_primitives *)mp->b_rptr)->type);
7097c478bd9Sstevel@tonic-gate #endif
7107c478bd9Sstevel@tonic-gate 			freemsg(mp);
7117c478bd9Sstevel@tonic-gate 		}
7127c478bd9Sstevel@tonic-gate 		break;
7137c478bd9Sstevel@tonic-gate 
7147c478bd9Sstevel@tonic-gate 	case M_PCPROTO:
7157c478bd9Sstevel@tonic-gate 		if (((struct T_exdata_req *)mp->b_rptr)->PRIM_type ==
7167c478bd9Sstevel@tonic-gate 		    T_DISCON_REQ) {
7177c478bd9Sstevel@tonic-gate 			putnext(q, mp);
7187c478bd9Sstevel@tonic-gate 		} else {
7197c478bd9Sstevel@tonic-gate 			/* XXX.sparker Log unexpected message */
7207c478bd9Sstevel@tonic-gate 			freemsg(mp);
7217c478bd9Sstevel@tonic-gate 		}
7227c478bd9Sstevel@tonic-gate 		break;
7237c478bd9Sstevel@tonic-gate 
7247c478bd9Sstevel@tonic-gate 	default:
7257c478bd9Sstevel@tonic-gate #ifdef DEBUG
7267c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE,
7277c478bd9Sstevel@tonic-gate 		    "rlmodwput: unexpected msg type 0x%x",
7287c478bd9Sstevel@tonic-gate 		    mp->b_datap->db_type);
7297c478bd9Sstevel@tonic-gate #endif
7307c478bd9Sstevel@tonic-gate 		freemsg(mp);
7317c478bd9Sstevel@tonic-gate 		break;
7327c478bd9Sstevel@tonic-gate 	}
7337c478bd9Sstevel@tonic-gate 	TRACE_3(TR_FAC_RLOGINP, TR_RLOGINP_WPUT_OUT, "rlmodwput end: "
7347c478bd9Sstevel@tonic-gate 	    "q %p, mp %p, %s", q, mp, "done");
7357c478bd9Sstevel@tonic-gate 	return (0);
7367c478bd9Sstevel@tonic-gate }
7377c478bd9Sstevel@tonic-gate 
7387c478bd9Sstevel@tonic-gate /*
7397c478bd9Sstevel@tonic-gate  * rlmodwsrv - module write service procedure
7407c478bd9Sstevel@tonic-gate  */
7417c478bd9Sstevel@tonic-gate static int
rlmodwsrv(queue_t * q)7427c478bd9Sstevel@tonic-gate rlmodwsrv(queue_t *q)
7437c478bd9Sstevel@tonic-gate {
7447c478bd9Sstevel@tonic-gate 	mblk_t	*mp, *tmpmp;
7457c478bd9Sstevel@tonic-gate 	char cntl;
7467c478bd9Sstevel@tonic-gate 	struct rlmod_info *rmip = (struct rlmod_info *)q->q_ptr;
7477c478bd9Sstevel@tonic-gate 
7487c478bd9Sstevel@tonic-gate 	TRACE_1(TR_FAC_RLOGINP, TR_RLOGINP_WSRV_IN, "rlmodwsrv "
7497c478bd9Sstevel@tonic-gate 	    "start: q %p", q);
7507c478bd9Sstevel@tonic-gate 	if (rmip->rl_expdat) {
7517c478bd9Sstevel@tonic-gate 		/*
7527c478bd9Sstevel@tonic-gate 		 * call make_expmblk to create an expedited
7537c478bd9Sstevel@tonic-gate 		 * message block.
7547c478bd9Sstevel@tonic-gate 		 */
7557c478bd9Sstevel@tonic-gate 		cntl = rmip->oobdata[0] | TIOCPKT_FLUSHWRITE;
7567c478bd9Sstevel@tonic-gate 		if (!canputnext(q)) {
7577c478bd9Sstevel@tonic-gate 			TRACE_3(TR_FAC_RLOGINP, TR_RLOGINP_WSRV_OUT,
7587c478bd9Sstevel@tonic-gate 			    "rlmodwsrv end: q %p, mp %p, %s",
7597c478bd9Sstevel@tonic-gate 			    q, NULL, "!canputnext && expdat");
7607c478bd9Sstevel@tonic-gate 			return (0);
7617c478bd9Sstevel@tonic-gate 		}
7627c478bd9Sstevel@tonic-gate 		if ((tmpmp = make_expmblk(cntl))) {
7637c478bd9Sstevel@tonic-gate 			putnext(q, tmpmp);
7647c478bd9Sstevel@tonic-gate 			rmip->rl_expdat = 0;
7657c478bd9Sstevel@tonic-gate 		} else {
7667c478bd9Sstevel@tonic-gate 			recover1(q, sizeof (mblk_t));
7677c478bd9Sstevel@tonic-gate 			TRACE_3(TR_FAC_RLOGINP, TR_RLOGINP_WSRV_OUT,
7687c478bd9Sstevel@tonic-gate 			    "rlmodwsrv end: q %p, mp %p, %s",
7697c478bd9Sstevel@tonic-gate 			    q, NULL, "!make_expmblk");
7707c478bd9Sstevel@tonic-gate 			return (0);
7717c478bd9Sstevel@tonic-gate 		}
7727c478bd9Sstevel@tonic-gate 	}
7737c478bd9Sstevel@tonic-gate 	while ((mp = getq(q)) != NULL) {
7747c478bd9Sstevel@tonic-gate 
7757c478bd9Sstevel@tonic-gate 		if (!canputnext(q) || rmip->rl_expdat) {
7767c478bd9Sstevel@tonic-gate 			(void) putbq(q, mp);
7777c478bd9Sstevel@tonic-gate 			TRACE_3(TR_FAC_RLOGINP, TR_RLOGINP_WSRV_OUT,
7787c478bd9Sstevel@tonic-gate 			    "rlmodwsrv end: q %p, mp %p, %s",
7797c478bd9Sstevel@tonic-gate 			    q, mp, "!canputnext || expdat");
7807c478bd9Sstevel@tonic-gate 			return (0);
7817c478bd9Sstevel@tonic-gate 		}
7827c478bd9Sstevel@tonic-gate 		if (mp->b_datap->db_type == M_IOCTL) {
7837c478bd9Sstevel@tonic-gate 			if (!rlmodwioctl(q, mp)) {
7847c478bd9Sstevel@tonic-gate 				TRACE_3(TR_FAC_RLOGINP, TR_RLOGINP_WSRV_OUT,
7857c478bd9Sstevel@tonic-gate 				    "rlmodwsrv end: q %p, mp %p, %s",
7867c478bd9Sstevel@tonic-gate 				    q, mp, "!rlmodwioctl");
7877c478bd9Sstevel@tonic-gate 				(void) putbq(q, mp);
7887c478bd9Sstevel@tonic-gate 				return (0);
7897c478bd9Sstevel@tonic-gate 			}
7907c478bd9Sstevel@tonic-gate 			continue;
7917c478bd9Sstevel@tonic-gate 		}
7927c478bd9Sstevel@tonic-gate 		putnext(q, mp);
7937c478bd9Sstevel@tonic-gate 	}
7947c478bd9Sstevel@tonic-gate 	TRACE_3(TR_FAC_RLOGINP, TR_RLOGINP_WSRV_OUT, "rlmodwsrv end: q %p, "
7957c478bd9Sstevel@tonic-gate 	    "mp %p, %s", q, mp, "done");
7967c478bd9Sstevel@tonic-gate 	return (0);
7977c478bd9Sstevel@tonic-gate }
7987c478bd9Sstevel@tonic-gate 
7997c478bd9Sstevel@tonic-gate /*
8007c478bd9Sstevel@tonic-gate  * This routine returns a message block with an expedited
8017c478bd9Sstevel@tonic-gate  * data request
8027c478bd9Sstevel@tonic-gate  */
8037c478bd9Sstevel@tonic-gate static mblk_t *
make_expmblk(char cntl)8047c478bd9Sstevel@tonic-gate make_expmblk(char cntl)
8057c478bd9Sstevel@tonic-gate {
8067c478bd9Sstevel@tonic-gate 	mblk_t *mp;
8077c478bd9Sstevel@tonic-gate 	mblk_t *bp;
8087c478bd9Sstevel@tonic-gate 	struct T_exdata_req	*data_req;
8097c478bd9Sstevel@tonic-gate 
8107c478bd9Sstevel@tonic-gate 	bp = allocb(sizeof (struct T_exdata_req), BPRI_MED);
8117c478bd9Sstevel@tonic-gate 	if (bp == NULL)
8127c478bd9Sstevel@tonic-gate 		return (NULL);
8137c478bd9Sstevel@tonic-gate 	if ((mp = allocb(sizeof (char), BPRI_MED)) == NULL) {
8147c478bd9Sstevel@tonic-gate 		freeb(bp);
8157c478bd9Sstevel@tonic-gate 		return (NULL);
8167c478bd9Sstevel@tonic-gate 	}
8177c478bd9Sstevel@tonic-gate 	bp->b_datap->db_type = M_PROTO;
8187c478bd9Sstevel@tonic-gate 	data_req = (struct T_exdata_req *)bp->b_rptr;
8197c478bd9Sstevel@tonic-gate 	data_req->PRIM_type = T_EXDATA_REQ;
8207c478bd9Sstevel@tonic-gate 	data_req->MORE_flag = 0;
8217c478bd9Sstevel@tonic-gate 
8227c478bd9Sstevel@tonic-gate 	bp->b_wptr += sizeof (struct T_exdata_req);
8237c478bd9Sstevel@tonic-gate 	/*
8247c478bd9Sstevel@tonic-gate 	 * Send a 1 byte data message block with appropriate
8257c478bd9Sstevel@tonic-gate 	 * control character.
8267c478bd9Sstevel@tonic-gate 	 */
8277c478bd9Sstevel@tonic-gate 	mp->b_datap->db_type = M_DATA;
8287c478bd9Sstevel@tonic-gate 	mp->b_wptr = mp->b_rptr + 1;
8297c478bd9Sstevel@tonic-gate 	(*(char *)(mp->b_rptr)) = cntl;
8307c478bd9Sstevel@tonic-gate 	bp->b_cont = mp;
8317c478bd9Sstevel@tonic-gate 	return (bp);
8327c478bd9Sstevel@tonic-gate }
8337c478bd9Sstevel@tonic-gate /*
8347c478bd9Sstevel@tonic-gate  * This routine parses M_DATA messages checking for window size protocol
8357c478bd9Sstevel@tonic-gate  * from a given message block.  It returns TRUE if no resource exhaustion
8367c478bd9Sstevel@tonic-gate  * conditions are found.  This is for use in the service procedure, which
8377c478bd9Sstevel@tonic-gate  * needs to know whether to continue, or stop processing the queue.
8387c478bd9Sstevel@tonic-gate  */
8397c478bd9Sstevel@tonic-gate static int
rlmodrmsg(queue_t * q,mblk_t * mp)8407c478bd9Sstevel@tonic-gate rlmodrmsg(queue_t *q, mblk_t *mp)
8417c478bd9Sstevel@tonic-gate {
8427c478bd9Sstevel@tonic-gate 	unsigned char *tmp, *tmp1;
8437c478bd9Sstevel@tonic-gate 	mblk_t	*newmp;
8447c478bd9Sstevel@tonic-gate 	size_t	sz;
8457c478bd9Sstevel@tonic-gate 	ssize_t	count, newcount = 0;
8467c478bd9Sstevel@tonic-gate 	struct	rlmod_info	*rmip = (struct rlmod_info *)q->q_ptr;
8477c478bd9Sstevel@tonic-gate 
8487c478bd9Sstevel@tonic-gate 	/*
8497c478bd9Sstevel@tonic-gate 	 * Eliminate any zero length messages here, so we don't filter EOFs
8507c478bd9Sstevel@tonic-gate 	 * accidentally.
8517c478bd9Sstevel@tonic-gate 	 */
8527c478bd9Sstevel@tonic-gate 	if (msgdsize(mp) == 0) {
8537c478bd9Sstevel@tonic-gate 		ASSERT(rmip->wndw_sz_hd_mp == NULL);
8547c478bd9Sstevel@tonic-gate 		goto out;
8557c478bd9Sstevel@tonic-gate 	}
8567c478bd9Sstevel@tonic-gate 	/*
8577c478bd9Sstevel@tonic-gate 	 * Check if we have stored a previous message block because a window
8587c478bd9Sstevel@tonic-gate 	 * update was split over TCP segments. If so, append the new one to
8597c478bd9Sstevel@tonic-gate 	 * the stored one and process the stored one as if it just arrived.
8607c478bd9Sstevel@tonic-gate 	 */
8617c478bd9Sstevel@tonic-gate 	if (rmip->wndw_sz_hd_mp != NULL) {
8627c478bd9Sstevel@tonic-gate 		linkb(rmip->wndw_sz_hd_mp, mp);
8637c478bd9Sstevel@tonic-gate 		mp = rmip->wndw_sz_hd_mp;
8647c478bd9Sstevel@tonic-gate 		rmip->wndw_sz_hd_mp = NULL;
8657c478bd9Sstevel@tonic-gate 	}
8667c478bd9Sstevel@tonic-gate 	newmp = mp;
8677c478bd9Sstevel@tonic-gate 
8687c478bd9Sstevel@tonic-gate 	while (mp) {
8697c478bd9Sstevel@tonic-gate 		tmp = mp->b_rptr;
8707c478bd9Sstevel@tonic-gate 		/*
8717c478bd9Sstevel@tonic-gate 		 * scan through the entire message block
8727c478bd9Sstevel@tonic-gate 		 */
8737c478bd9Sstevel@tonic-gate 		while (tmp < mp->b_wptr) {
8747c478bd9Sstevel@tonic-gate 			/*
8757c478bd9Sstevel@tonic-gate 			 * check for FF (rlogin magic escape sequence)
8767c478bd9Sstevel@tonic-gate 			 */
8777c478bd9Sstevel@tonic-gate 			if (tmp[0] == RLOGIN_MAGIC) {
8787c478bd9Sstevel@tonic-gate 				/*
8797c478bd9Sstevel@tonic-gate 				 * Update bytes read so far.
8807c478bd9Sstevel@tonic-gate 				 */
8817c478bd9Sstevel@tonic-gate 				count = newcount + tmp - mp->b_rptr;
8827c478bd9Sstevel@tonic-gate 				/*
8837c478bd9Sstevel@tonic-gate 				 * Pull together message chain in case
8847c478bd9Sstevel@tonic-gate 				 * window escape is split across blocks.
8857c478bd9Sstevel@tonic-gate 				 */
8867c478bd9Sstevel@tonic-gate 				if ((pullupmsg(newmp, -1)) == 0) {
8877c478bd9Sstevel@tonic-gate 					sz = msgdsize(newmp);
8887c478bd9Sstevel@tonic-gate 					recover(q, newmp, sz);
889*a8eee26aSToomas Soome 					return (0);
8907c478bd9Sstevel@tonic-gate 				}
8917c478bd9Sstevel@tonic-gate 				/*
8927c478bd9Sstevel@tonic-gate 				 * pullupmsg results in newmp consuming
8937c478bd9Sstevel@tonic-gate 				 * all message blocks in this chain, and
8947c478bd9Sstevel@tonic-gate 				 * therefor mp wants updating.
8957c478bd9Sstevel@tonic-gate 				 */
8967c478bd9Sstevel@tonic-gate 				mp = newmp;
8977c478bd9Sstevel@tonic-gate 
8987c478bd9Sstevel@tonic-gate 				/*
8997c478bd9Sstevel@tonic-gate 				 * adjust tmp to where we
9007c478bd9Sstevel@tonic-gate 				 * stopped - count keeps track
9017c478bd9Sstevel@tonic-gate 				 * of bytes read so far.
9027c478bd9Sstevel@tonic-gate 				 * reset newcount = 0.
9037c478bd9Sstevel@tonic-gate 				 */
9047c478bd9Sstevel@tonic-gate 				tmp = mp->b_rptr + count;
9057c478bd9Sstevel@tonic-gate 				newcount = 0;
9067c478bd9Sstevel@tonic-gate 
9077c478bd9Sstevel@tonic-gate 				/*
9087c478bd9Sstevel@tonic-gate 				 * Use the variable tmp1 to compute where
9097c478bd9Sstevel@tonic-gate 				 * the end of the window escape (currently
9107c478bd9Sstevel@tonic-gate 				 * the only rlogin protocol sequence), then
9117c478bd9Sstevel@tonic-gate 				 * check to see if we got all those bytes.
9127c478bd9Sstevel@tonic-gate 				 */
9137c478bd9Sstevel@tonic-gate 				tmp1 = tmp + 4 + sizeof (struct winsize);
9147c478bd9Sstevel@tonic-gate 
9157c478bd9Sstevel@tonic-gate 				if (tmp1 > mp->b_wptr) {
9167c478bd9Sstevel@tonic-gate 					/*
9177c478bd9Sstevel@tonic-gate 					 * All the window escape bytes aren't
9187c478bd9Sstevel@tonic-gate 					 * in this TCP segment. Store this
9197c478bd9Sstevel@tonic-gate 					 * mblk to one side so we can append
9207c478bd9Sstevel@tonic-gate 					 * the rest of the escape to it when
9217c478bd9Sstevel@tonic-gate 					 * its segment arrives.
9227c478bd9Sstevel@tonic-gate 					 */
9237c478bd9Sstevel@tonic-gate 					rmip->wndw_sz_hd_mp = mp;
9247c478bd9Sstevel@tonic-gate 					return (TRUE);
9257c478bd9Sstevel@tonic-gate 				}
9267c478bd9Sstevel@tonic-gate 				/*
9277c478bd9Sstevel@tonic-gate 				 * check for FF FF s s pattern
9287c478bd9Sstevel@tonic-gate 				 */
9297c478bd9Sstevel@tonic-gate 				if ((tmp[1] == RLOGIN_MAGIC) &&
9307c478bd9Sstevel@tonic-gate 				    (tmp[2] == 's') && (tmp[3] == 's')) {
9317c478bd9Sstevel@tonic-gate 
9327c478bd9Sstevel@tonic-gate 					/*
9337c478bd9Sstevel@tonic-gate 					 * If rlwinsetup returns an error,
9347c478bd9Sstevel@tonic-gate 					 * we do recover with newmp which
9357c478bd9Sstevel@tonic-gate 					 * points to new chain of mblks after
9367c478bd9Sstevel@tonic-gate 					 * doing window control ioctls.
9377c478bd9Sstevel@tonic-gate 					 * rlwinsetup returns newmp which
9387c478bd9Sstevel@tonic-gate 					 * contains only data part.
9397c478bd9Sstevel@tonic-gate 					 * Note that buried inside rlwinsetup
9407c478bd9Sstevel@tonic-gate 					 * is where we do the putnext.
9417c478bd9Sstevel@tonic-gate 					 */
9427c478bd9Sstevel@tonic-gate 					if (rlwinsetup(q, mp, tmp) == NULL) {
9437c478bd9Sstevel@tonic-gate 						sz = msgdsize(mp);
9447c478bd9Sstevel@tonic-gate 						recover(q, mp, sz);
945*a8eee26aSToomas Soome 						return (0);
9467c478bd9Sstevel@tonic-gate 					}
9477c478bd9Sstevel@tonic-gate 					/*
9487c478bd9Sstevel@tonic-gate 					 * We have successfully consumed the
9497c478bd9Sstevel@tonic-gate 					 * window sequence, but rlwinsetup()
9507c478bd9Sstevel@tonic-gate 					 * and its children have moved memory
9517c478bd9Sstevel@tonic-gate 					 * up underneath us.  This means that
9527c478bd9Sstevel@tonic-gate 					 * the byte underneath *tmp has not
9537c478bd9Sstevel@tonic-gate 					 * been scanned now.  We will now need
9547c478bd9Sstevel@tonic-gate 					 * to rescan it.
9557c478bd9Sstevel@tonic-gate 					 */
9567c478bd9Sstevel@tonic-gate 					continue;
9577c478bd9Sstevel@tonic-gate 				}
9587c478bd9Sstevel@tonic-gate 			}
9597c478bd9Sstevel@tonic-gate 			tmp++;
9607c478bd9Sstevel@tonic-gate 		}
9617c478bd9Sstevel@tonic-gate 		/*
9627c478bd9Sstevel@tonic-gate 		 * bump newcount to include size of this particular block.
9637c478bd9Sstevel@tonic-gate 		 */
9647c478bd9Sstevel@tonic-gate 		newcount += (mp->b_wptr - mp->b_rptr);
9657c478bd9Sstevel@tonic-gate 		mp = mp->b_cont;
9667c478bd9Sstevel@tonic-gate 	}
9677c478bd9Sstevel@tonic-gate 	/*
9687c478bd9Sstevel@tonic-gate 	 * If we trimmed the message down to nothing to forward, don't
9697c478bd9Sstevel@tonic-gate 	 * send any M_DATA message.  (Don't want to send EOF!)
9707c478bd9Sstevel@tonic-gate 	 */
9717c478bd9Sstevel@tonic-gate 	if (msgdsize(newmp) == 0) {
9727c478bd9Sstevel@tonic-gate 		freemsg(newmp);
9737c478bd9Sstevel@tonic-gate 		newmp = NULL;
9747c478bd9Sstevel@tonic-gate 	}
9757c478bd9Sstevel@tonic-gate out:
9767c478bd9Sstevel@tonic-gate 	if (newmp) {
9777c478bd9Sstevel@tonic-gate 		if (!canputnext(q)) {
9787c478bd9Sstevel@tonic-gate 			(void) putbq(q, newmp);
979*a8eee26aSToomas Soome 			return (0);
9807c478bd9Sstevel@tonic-gate 		} else {
9817c478bd9Sstevel@tonic-gate 			putnext(q, newmp);
9827c478bd9Sstevel@tonic-gate 		}
9837c478bd9Sstevel@tonic-gate 	}
9847c478bd9Sstevel@tonic-gate 	return (TRUE);
9857c478bd9Sstevel@tonic-gate }
9867c478bd9Sstevel@tonic-gate 
9877c478bd9Sstevel@tonic-gate 
9887c478bd9Sstevel@tonic-gate /*
9897c478bd9Sstevel@tonic-gate  * This routine is called to handle window size changes.
9907c478bd9Sstevel@tonic-gate  * The routine returns 1 on success and 0 on error (allocb failure).
9917c478bd9Sstevel@tonic-gate  */
9927c478bd9Sstevel@tonic-gate static int
rlwinctl(queue_t * q,mblk_t * mp)9937c478bd9Sstevel@tonic-gate rlwinctl(queue_t *q, mblk_t *mp)
9947c478bd9Sstevel@tonic-gate {
9957c478bd9Sstevel@tonic-gate 	mblk_t	*rl_msgp;
9967c478bd9Sstevel@tonic-gate 	struct	iocblk	*iocbp;
9977c478bd9Sstevel@tonic-gate 	struct	rlmod_info	*rmip = (struct rlmod_info *)q->q_ptr;
9987c478bd9Sstevel@tonic-gate 
9997c478bd9Sstevel@tonic-gate 	TRACE_2(TR_FAC_RLOGINP, TR_RLOGINP_WINCTL_IN, "rlwinctl start: q %p, "
10007c478bd9Sstevel@tonic-gate 	    "mp %p", q, mp);
10017c478bd9Sstevel@tonic-gate 
100248bbca81SDaniel Hoffman 	rmip->oobdata[0] &= ~TIOCPKT_WINDOW; /* we know they heard */
10037c478bd9Sstevel@tonic-gate 
10047c478bd9Sstevel@tonic-gate 	if ((rl_msgp = mkiocb(TIOCSWINSZ)) == NULL) {
10057c478bd9Sstevel@tonic-gate 		TRACE_2(TR_FAC_RLOGINP, TR_RLOGINP_WINCTL_OUT, "rlwinctl end: "
10067c478bd9Sstevel@tonic-gate 		    "q %p, mp %p, allocb failed", q, mp);
10077c478bd9Sstevel@tonic-gate 		return (0);
10087c478bd9Sstevel@tonic-gate 	}
10097c478bd9Sstevel@tonic-gate 
10107c478bd9Sstevel@tonic-gate 	/*
10117c478bd9Sstevel@tonic-gate 	 * create an M_IOCTL message type.
10127c478bd9Sstevel@tonic-gate 	 */
10137c478bd9Sstevel@tonic-gate 	rl_msgp->b_cont = mp;
10147c478bd9Sstevel@tonic-gate 	iocbp = (struct iocblk *)rl_msgp->b_rptr;
10157c478bd9Sstevel@tonic-gate 	iocbp->ioc_count = msgdsize(mp);
10167c478bd9Sstevel@tonic-gate 
10177c478bd9Sstevel@tonic-gate 	putnext(q, rl_msgp);
10187c478bd9Sstevel@tonic-gate 	TRACE_2(TR_FAC_RLOGINP, TR_RLOGINP_WINCTL_OUT, "rlwinctl end: "
10197c478bd9Sstevel@tonic-gate 	    "q %p, mp %p, done", q, mp);
10207c478bd9Sstevel@tonic-gate 	return (1);
10217c478bd9Sstevel@tonic-gate }
10227c478bd9Sstevel@tonic-gate 
10237c478bd9Sstevel@tonic-gate /*
10247c478bd9Sstevel@tonic-gate  * This routine sets up window size change protocol.
10257c478bd9Sstevel@tonic-gate  * The routine returns the new mblk after issuing rlwinctl
10267c478bd9Sstevel@tonic-gate  * for window size changes. New mblk contains only data part
10277c478bd9Sstevel@tonic-gate  * of the message block. The routine returns 0 on error.
10287c478bd9Sstevel@tonic-gate  */
10297c478bd9Sstevel@tonic-gate static mblk_t *
rlwinsetup(queue_t * q,mblk_t * mp,unsigned char * blk)10307c478bd9Sstevel@tonic-gate rlwinsetup(queue_t *q, mblk_t *mp, unsigned char *blk)
10317c478bd9Sstevel@tonic-gate {
10327c478bd9Sstevel@tonic-gate 	mblk_t		*mp1;
10337c478bd9Sstevel@tonic-gate 	unsigned char	*jmpmp;
10347c478bd9Sstevel@tonic-gate 	ssize_t		left = 0;
10357c478bd9Sstevel@tonic-gate 	struct winsize	win;
10367c478bd9Sstevel@tonic-gate 
10377c478bd9Sstevel@tonic-gate 	/*
10387c478bd9Sstevel@tonic-gate 	 * Set jmpmp to where to jump, to get just past the end of the
10397c478bd9Sstevel@tonic-gate 	 * window size protocol sequence.
10407c478bd9Sstevel@tonic-gate 	 */
10417c478bd9Sstevel@tonic-gate 	jmpmp = (blk + 4 + sizeof (struct winsize));
10427c478bd9Sstevel@tonic-gate 	left = mp->b_wptr - jmpmp;
10437c478bd9Sstevel@tonic-gate 
10447c478bd9Sstevel@tonic-gate 	if ((mp1 = allocb(sizeof (struct winsize), BPRI_MED)) == NULL)
10457c478bd9Sstevel@tonic-gate 		return (0);
10467c478bd9Sstevel@tonic-gate 	mp1->b_datap->db_type = M_DATA;
10477c478bd9Sstevel@tonic-gate 	mp1->b_wptr = mp1->b_rptr + sizeof (struct winsize);
10487c478bd9Sstevel@tonic-gate 	bcopy(blk + 4, &win, sizeof (struct winsize));
10497c478bd9Sstevel@tonic-gate 	win.ws_row = ntohs(win.ws_row);
10507c478bd9Sstevel@tonic-gate 	win.ws_col = ntohs(win.ws_col);
10517c478bd9Sstevel@tonic-gate 	win.ws_xpixel = ntohs(win.ws_xpixel);
10527c478bd9Sstevel@tonic-gate 	win.ws_ypixel = ntohs(win.ws_ypixel);
10537c478bd9Sstevel@tonic-gate 	bcopy(&win, mp1->b_rptr, sizeof (struct winsize));
10547c478bd9Sstevel@tonic-gate 
1055*a8eee26aSToomas Soome 	if ((rlwinctl(q, mp1)) == 0) {
10567c478bd9Sstevel@tonic-gate 		freeb(mp1);
10577c478bd9Sstevel@tonic-gate 		return (0);
10587c478bd9Sstevel@tonic-gate 	}
10597c478bd9Sstevel@tonic-gate 	if (left > 0) {
10607c478bd9Sstevel@tonic-gate 		/*
10617c478bd9Sstevel@tonic-gate 		 * Must delete the window size protocol sequence.  We do
10627c478bd9Sstevel@tonic-gate 		 * this by sliding all the stuff after the sequence (jmpmp)
10637c478bd9Sstevel@tonic-gate 		 * to where the sequence itself began (blk).
10647c478bd9Sstevel@tonic-gate 		 */
10657c478bd9Sstevel@tonic-gate 		bcopy(jmpmp, blk, left);
10667c478bd9Sstevel@tonic-gate 		mp->b_wptr = blk + left;
10677c478bd9Sstevel@tonic-gate 	} else
10687c478bd9Sstevel@tonic-gate 		mp->b_wptr = blk;
10697c478bd9Sstevel@tonic-gate 	return (mp);
10707c478bd9Sstevel@tonic-gate }
10717c478bd9Sstevel@tonic-gate 
10727c478bd9Sstevel@tonic-gate /*
10737c478bd9Sstevel@tonic-gate  * When an ioctl changes software flow control on the tty, we must notify
10747c478bd9Sstevel@tonic-gate  * the rlogin client, so it can adjust its behavior appropriately.  This
10757c478bd9Sstevel@tonic-gate  * routine, called from either the put or service routine, determines if
10767c478bd9Sstevel@tonic-gate  * the flow handling has changed.  If so, it tries to send the indication
10777c478bd9Sstevel@tonic-gate  * to the client.  It returns true or false depending upon whether the
10787c478bd9Sstevel@tonic-gate  * message was fully processed.  If it wasn't fully processed it queues
10797c478bd9Sstevel@tonic-gate  * the message for retry later when resources
10807c478bd9Sstevel@tonic-gate  * (allocb/canputnext) are available.
10817c478bd9Sstevel@tonic-gate  */
10827c478bd9Sstevel@tonic-gate static boolean_t
tty_flow(queue_t * q,struct rlmod_info * rmip,mblk_t * mp)10837c478bd9Sstevel@tonic-gate tty_flow(queue_t *q, struct rlmod_info *rmip, mblk_t *mp)
10847c478bd9Sstevel@tonic-gate {
10857c478bd9Sstevel@tonic-gate 	struct iocblk *ioc;
10867c478bd9Sstevel@tonic-gate 	struct termios *tp;
10877c478bd9Sstevel@tonic-gate 	struct termio *ti;
10887c478bd9Sstevel@tonic-gate 	int stop, ixon;
10897c478bd9Sstevel@tonic-gate 	mblk_t *tmpmp;
10907c478bd9Sstevel@tonic-gate 	char cntl;
10917c478bd9Sstevel@tonic-gate 	int error;
10927c478bd9Sstevel@tonic-gate 
10937c478bd9Sstevel@tonic-gate 	ioc = (struct iocblk *)mp->b_rptr;
10947c478bd9Sstevel@tonic-gate 	switch (ioc->ioc_cmd) {
10957c478bd9Sstevel@tonic-gate 
10967c478bd9Sstevel@tonic-gate 	/*
10977c478bd9Sstevel@tonic-gate 	 * If it is a tty ioctl, save the output flow
10987c478bd9Sstevel@tonic-gate 	 * control flag and the start and stop flow control
10997c478bd9Sstevel@tonic-gate 	 * characters if they are available.
11007c478bd9Sstevel@tonic-gate 	 */
11017c478bd9Sstevel@tonic-gate 	case TCSETS:
11027c478bd9Sstevel@tonic-gate 	case TCSETSW:
11037c478bd9Sstevel@tonic-gate 	case TCSETSF:
11047c478bd9Sstevel@tonic-gate 		error = miocpullup(mp, sizeof (struct termios));
11057c478bd9Sstevel@tonic-gate 		if (error != 0) {
11067c478bd9Sstevel@tonic-gate 			miocnak(q, mp, 0, error);
11077c478bd9Sstevel@tonic-gate 			return (B_TRUE);
11087c478bd9Sstevel@tonic-gate 		}
11097c478bd9Sstevel@tonic-gate 		tp = (struct termios *)(mp->b_cont->b_rptr);
11107c478bd9Sstevel@tonic-gate 		rmip->stopc = tp->c_cc[VSTOP];
11117c478bd9Sstevel@tonic-gate 		rmip->startc = tp->c_cc[VSTART];
11127c478bd9Sstevel@tonic-gate 		ixon = tp->c_iflag & IXON;
11137c478bd9Sstevel@tonic-gate 		break;
11147c478bd9Sstevel@tonic-gate 
11157c478bd9Sstevel@tonic-gate 	case TCSETA:
11167c478bd9Sstevel@tonic-gate 	case TCSETAW:
11177c478bd9Sstevel@tonic-gate 	case TCSETAF:
11187c478bd9Sstevel@tonic-gate 		error = miocpullup(mp, sizeof (struct termio));
11197c478bd9Sstevel@tonic-gate 		if (error != 0) {
11207c478bd9Sstevel@tonic-gate 			miocnak(q, mp, 0, error);
11217c478bd9Sstevel@tonic-gate 			return (B_TRUE);
11227c478bd9Sstevel@tonic-gate 		}
11237c478bd9Sstevel@tonic-gate 		ti = (struct termio *)(mp->b_cont->b_rptr);
11247c478bd9Sstevel@tonic-gate 		ixon = ti->c_iflag & IXON;
11257c478bd9Sstevel@tonic-gate 		break;
11267c478bd9Sstevel@tonic-gate 
11277c478bd9Sstevel@tonic-gate 	default:
11287c478bd9Sstevel@tonic-gate 		/*
11297c478bd9Sstevel@tonic-gate 		 * This function must never be called for an M_IOCTL
11307c478bd9Sstevel@tonic-gate 		 * except the listed ones.
11317c478bd9Sstevel@tonic-gate 		 */
11327c478bd9Sstevel@tonic-gate #ifdef DEBUG
11337c478bd9Sstevel@tonic-gate 		cmn_err(CE_PANIC,
11347c478bd9Sstevel@tonic-gate 		    "rloginmod: tty_flow: bad ioctl 0x%x", ioc->ioc_cmd);
11357c478bd9Sstevel@tonic-gate #else
11367c478bd9Sstevel@tonic-gate 		miocnak(q, mp, 0, EINVAL);
11377c478bd9Sstevel@tonic-gate 		return (B_TRUE);
11387c478bd9Sstevel@tonic-gate #endif
11397c478bd9Sstevel@tonic-gate 	}
11407c478bd9Sstevel@tonic-gate 	/*
11417c478bd9Sstevel@tonic-gate 	 * If tty ioctl processing is done, check for stopmode
11427c478bd9Sstevel@tonic-gate 	 */
11437c478bd9Sstevel@tonic-gate 	stop = (ixon && (rmip->stopc == CTRL('s')) &&
1144*a8eee26aSToomas Soome 	    (rmip->startc == CTRL('q')));
11457c478bd9Sstevel@tonic-gate 	if (rmip->stopmode == TIOCPKT_NOSTOP) {
11467c478bd9Sstevel@tonic-gate 		if (stop) {
11477c478bd9Sstevel@tonic-gate 			cntl = rmip->oobdata[0] | TIOCPKT_DOSTOP;
11487c478bd9Sstevel@tonic-gate 			if ((tmpmp = make_expmblk(cntl)) == NULL) {
11497c478bd9Sstevel@tonic-gate 				recover(q, mp, sizeof (mblk_t));
11507c478bd9Sstevel@tonic-gate 				return (B_FALSE);
11517c478bd9Sstevel@tonic-gate 			}
11527c478bd9Sstevel@tonic-gate 			if (!canputnext(q)) {
11537c478bd9Sstevel@tonic-gate 				freemsg(tmpmp);
11547c478bd9Sstevel@tonic-gate 				return (B_FALSE);
11557c478bd9Sstevel@tonic-gate 			}
11567c478bd9Sstevel@tonic-gate 			putnext(q, tmpmp);
11577c478bd9Sstevel@tonic-gate 			rmip->stopmode = TIOCPKT_DOSTOP;
11587c478bd9Sstevel@tonic-gate 		}
11597c478bd9Sstevel@tonic-gate 	} else {
11607c478bd9Sstevel@tonic-gate 		if (!stop) {
11617c478bd9Sstevel@tonic-gate 			cntl = rmip->oobdata[0] | TIOCPKT_NOSTOP;
11627c478bd9Sstevel@tonic-gate 			if ((tmpmp = make_expmblk(cntl)) == NULL) {
11637c478bd9Sstevel@tonic-gate 				recover(q, mp, sizeof (mblk_t));
11647c478bd9Sstevel@tonic-gate 				return (B_FALSE);
11657c478bd9Sstevel@tonic-gate 			}
11667c478bd9Sstevel@tonic-gate 			if (!canputnext(q)) {
11677c478bd9Sstevel@tonic-gate 				freemsg(tmpmp);
11687c478bd9Sstevel@tonic-gate 				return (B_FALSE);
11697c478bd9Sstevel@tonic-gate 			}
11707c478bd9Sstevel@tonic-gate 			putnext(q, tmpmp);
11717c478bd9Sstevel@tonic-gate 			rmip->stopmode = TIOCPKT_NOSTOP;
11727c478bd9Sstevel@tonic-gate 		}
11737c478bd9Sstevel@tonic-gate 	}
11747c478bd9Sstevel@tonic-gate 
11757c478bd9Sstevel@tonic-gate 	miocack(q, mp, 0, 0);
11767c478bd9Sstevel@tonic-gate 	return (B_TRUE);
11777c478bd9Sstevel@tonic-gate }
11787c478bd9Sstevel@tonic-gate 
11797c478bd9Sstevel@tonic-gate /* rlmodwioctl - handle M_IOCTL messages on the write queue. */
11807c478bd9Sstevel@tonic-gate 
11817c478bd9Sstevel@tonic-gate static boolean_t
rlmodwioctl(queue_t * q,mblk_t * mp)11827c478bd9Sstevel@tonic-gate rlmodwioctl(queue_t *q, mblk_t *mp)
11837c478bd9Sstevel@tonic-gate {
11847c478bd9Sstevel@tonic-gate 	struct iocblk *ioc;
11857c478bd9Sstevel@tonic-gate 	struct rlmod_info *rmip = (struct rlmod_info *)q->q_ptr;
11867c478bd9Sstevel@tonic-gate 	int error;
11877c478bd9Sstevel@tonic-gate 
11887c478bd9Sstevel@tonic-gate 	ioc = (struct iocblk *)mp->b_rptr;
11897c478bd9Sstevel@tonic-gate 	switch (ioc->ioc_cmd) {
11907c478bd9Sstevel@tonic-gate 
11917c478bd9Sstevel@tonic-gate 	/*
11927c478bd9Sstevel@tonic-gate 	 * This is a special ioctl to reenable the queue.
11937c478bd9Sstevel@tonic-gate 	 * The initial data read from the stream head is
11947c478bd9Sstevel@tonic-gate 	 * put back on the queue.
11957c478bd9Sstevel@tonic-gate 	 */
11967c478bd9Sstevel@tonic-gate 	case RL_IOC_ENABLE:
11977c478bd9Sstevel@tonic-gate 		/*
11987c478bd9Sstevel@tonic-gate 		 * Send negative ack if RL_DISABLED flag is not set
11997c478bd9Sstevel@tonic-gate 		 */
12007c478bd9Sstevel@tonic-gate 
12017c478bd9Sstevel@tonic-gate 		if (!(rmip->flags & RL_DISABLED)) {
12027c478bd9Sstevel@tonic-gate 			miocnak(q, mp, 0, EINVAL);
12037c478bd9Sstevel@tonic-gate 			break;
12047c478bd9Sstevel@tonic-gate 		}
12057c478bd9Sstevel@tonic-gate 		if (mp->b_cont) {
12067c478bd9Sstevel@tonic-gate 			(void) putbq(RD(q), mp->b_cont);
12077c478bd9Sstevel@tonic-gate 			mp->b_cont = NULL;
12087c478bd9Sstevel@tonic-gate 		}
12097c478bd9Sstevel@tonic-gate 
12107c478bd9Sstevel@tonic-gate 		if (rmip->flags & RL_DISABLED)
12117c478bd9Sstevel@tonic-gate 			rmip->flags &= ~RL_DISABLED;
12127c478bd9Sstevel@tonic-gate 		qenable(RD(q));
12137c478bd9Sstevel@tonic-gate 		miocack(q, mp, 0, 0);
12147c478bd9Sstevel@tonic-gate 		TRACE_3(TR_FAC_RLOGINP, TR_RLOGINP_WPUT_OUT,
12157c478bd9Sstevel@tonic-gate 		    "rlmodwput end: q %p, mp %p, %s",
12167c478bd9Sstevel@tonic-gate 		    q, mp, "IOCACK enable");
12177c478bd9Sstevel@tonic-gate 		return (B_TRUE);
12187c478bd9Sstevel@tonic-gate 
12197c478bd9Sstevel@tonic-gate 	/*
12207c478bd9Sstevel@tonic-gate 	 * If it is a tty ioctl, save the output flow
12217c478bd9Sstevel@tonic-gate 	 * control flag and the start and stop flow control
12227c478bd9Sstevel@tonic-gate 	 * characters if they are available.
12237c478bd9Sstevel@tonic-gate 	 */
12247c478bd9Sstevel@tonic-gate 	case TCSETS:
12257c478bd9Sstevel@tonic-gate 	case TCSETSW:
12267c478bd9Sstevel@tonic-gate 	case TCSETSF:
12277c478bd9Sstevel@tonic-gate 	case TCSETA:
12287c478bd9Sstevel@tonic-gate 	case TCSETAW:
12297c478bd9Sstevel@tonic-gate 	case TCSETAF:
12307c478bd9Sstevel@tonic-gate 		return (tty_flow(q, rmip, mp));
12317c478bd9Sstevel@tonic-gate 
12327c478bd9Sstevel@tonic-gate #ifdef DEBUG
12337c478bd9Sstevel@tonic-gate 	case TIOCSWINSZ:
12347c478bd9Sstevel@tonic-gate 	case TIOCSTI:
12357c478bd9Sstevel@tonic-gate 	case TCSBRK:
12367c478bd9Sstevel@tonic-gate 		miocnak(q, mp, 0, EINVAL);
12377c478bd9Sstevel@tonic-gate 		break;
12387c478bd9Sstevel@tonic-gate #endif
12397c478bd9Sstevel@tonic-gate 	case CRYPTPASSTHRU:
12407c478bd9Sstevel@tonic-gate 		error = miocpullup(mp, sizeof (uchar_t));
12417c478bd9Sstevel@tonic-gate 		if (error != 0) {
12427c478bd9Sstevel@tonic-gate 			miocnak(q, mp, 0, error);
12437c478bd9Sstevel@tonic-gate 			break;
12447c478bd9Sstevel@tonic-gate 		}
12457c478bd9Sstevel@tonic-gate 		if (*(mp->b_cont->b_rptr) == 0x01)
12467c478bd9Sstevel@tonic-gate 			rmip->flags |= RL_IOCPASSTHRU;
12477c478bd9Sstevel@tonic-gate 		else
12487c478bd9Sstevel@tonic-gate 			rmip->flags &= ~RL_IOCPASSTHRU;
12497c478bd9Sstevel@tonic-gate 
1250*a8eee26aSToomas Soome 		miocack(q, mp, 0, 0);
12517c478bd9Sstevel@tonic-gate 		break;
12527c478bd9Sstevel@tonic-gate 
12537c478bd9Sstevel@tonic-gate 	default:
12547c478bd9Sstevel@tonic-gate 		if (rmip->flags & RL_IOCPASSTHRU) {
12557c478bd9Sstevel@tonic-gate 			putnext(q, mp);
12567c478bd9Sstevel@tonic-gate 		} else {
12577c478bd9Sstevel@tonic-gate #ifdef DEBUG
12587c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE,
1259*a8eee26aSToomas Soome 			    "rlmodwioctl: unexpected ioctl type 0x%x",
1260*a8eee26aSToomas Soome 			    ioc->ioc_cmd);
12617c478bd9Sstevel@tonic-gate #endif
12627c478bd9Sstevel@tonic-gate 			miocnak(q, mp, 0, EINVAL);
12637c478bd9Sstevel@tonic-gate 		}
12647c478bd9Sstevel@tonic-gate 	}
12657c478bd9Sstevel@tonic-gate 	return (B_TRUE);
12667c478bd9Sstevel@tonic-gate }
12677c478bd9Sstevel@tonic-gate 
12687c478bd9Sstevel@tonic-gate static void
rlmod_timer(void * arg)12697c478bd9Sstevel@tonic-gate rlmod_timer(void *arg)
12707c478bd9Sstevel@tonic-gate {
12717c478bd9Sstevel@tonic-gate 	queue_t *q = arg;
12727c478bd9Sstevel@tonic-gate 	struct rlmod_info	*rmip = (struct rlmod_info *)q->q_ptr;
12737c478bd9Sstevel@tonic-gate 
12747c478bd9Sstevel@tonic-gate 	ASSERT(rmip);
12757c478bd9Sstevel@tonic-gate 	if (q->q_flag & QREADR) {
12767c478bd9Sstevel@tonic-gate 		ASSERT(rmip->rtimoutid);
12777c478bd9Sstevel@tonic-gate 		rmip->rtimoutid = 0;
12787c478bd9Sstevel@tonic-gate 	} else {
12797c478bd9Sstevel@tonic-gate 		ASSERT(rmip->wtimoutid);
12807c478bd9Sstevel@tonic-gate 		rmip->wtimoutid = 0;
12817c478bd9Sstevel@tonic-gate 	}
12827c478bd9Sstevel@tonic-gate 	enableok(q);
12837c478bd9Sstevel@tonic-gate 	qenable(q);
12847c478bd9Sstevel@tonic-gate }
12857c478bd9Sstevel@tonic-gate 
12867c478bd9Sstevel@tonic-gate static void
rlmod_buffer(void * arg)12877c478bd9Sstevel@tonic-gate rlmod_buffer(void *arg)
12887c478bd9Sstevel@tonic-gate {
12897c478bd9Sstevel@tonic-gate 	queue_t *q = arg;
12907c478bd9Sstevel@tonic-gate 	struct rlmod_info	*rmip = (struct rlmod_info *)q->q_ptr;
12917c478bd9Sstevel@tonic-gate 
12927c478bd9Sstevel@tonic-gate 	ASSERT(rmip);
12937c478bd9Sstevel@tonic-gate 	if (q->q_flag & QREADR) {
12947c478bd9Sstevel@tonic-gate 		ASSERT(rmip->rbufcid);
12957c478bd9Sstevel@tonic-gate 		rmip->rbufcid = 0;
12967c478bd9Sstevel@tonic-gate 	} else {
12977c478bd9Sstevel@tonic-gate 		ASSERT(rmip->wbufcid);
12987c478bd9Sstevel@tonic-gate 		rmip->wbufcid = 0;
12997c478bd9Sstevel@tonic-gate 	}
13007c478bd9Sstevel@tonic-gate 	enableok(q);
13017c478bd9Sstevel@tonic-gate 	qenable(q);
13027c478bd9Sstevel@tonic-gate }
13037c478bd9Sstevel@tonic-gate 
13047c478bd9Sstevel@tonic-gate static void
recover(queue_t * q,mblk_t * mp,size_t size)13057c478bd9Sstevel@tonic-gate recover(queue_t *q, mblk_t *mp, size_t size)
13067c478bd9Sstevel@tonic-gate {
13077c478bd9Sstevel@tonic-gate 	/*
13087c478bd9Sstevel@tonic-gate 	 * Avoid re-enabling the queue.
13097c478bd9Sstevel@tonic-gate 	 */
13107c478bd9Sstevel@tonic-gate 	ASSERT(mp->b_datap->db_type < QPCTL);
13117c478bd9Sstevel@tonic-gate 
13127c478bd9Sstevel@tonic-gate 	noenable(q);
13137c478bd9Sstevel@tonic-gate 	(void) putbq(q, mp);
13147c478bd9Sstevel@tonic-gate 	recover1(q, size);
13157c478bd9Sstevel@tonic-gate }
13167c478bd9Sstevel@tonic-gate 
13177c478bd9Sstevel@tonic-gate static void
recover1(queue_t * q,size_t size)13187c478bd9Sstevel@tonic-gate recover1(queue_t *q, size_t size)
13197c478bd9Sstevel@tonic-gate {
13207c478bd9Sstevel@tonic-gate 	struct rlmod_info	*rmip = (struct rlmod_info *)q->q_ptr;
13217c478bd9Sstevel@tonic-gate 	timeout_id_t	tid;
13227c478bd9Sstevel@tonic-gate 	bufcall_id_t	bid;
13237c478bd9Sstevel@tonic-gate 
13247c478bd9Sstevel@tonic-gate 	/*
13257c478bd9Sstevel@tonic-gate 	 * Make sure there is at most one outstanding request per queue.
13267c478bd9Sstevel@tonic-gate 	 */
13277c478bd9Sstevel@tonic-gate 	if (q->q_flag & QREADR) {
13287c478bd9Sstevel@tonic-gate 		if (rmip->rtimoutid || rmip->rbufcid)
13297c478bd9Sstevel@tonic-gate 			return;
13307c478bd9Sstevel@tonic-gate 	} else {
13317c478bd9Sstevel@tonic-gate 		if (rmip->wtimoutid || rmip->wbufcid)
13327c478bd9Sstevel@tonic-gate 			return;
13337c478bd9Sstevel@tonic-gate 	}
13347c478bd9Sstevel@tonic-gate 	if (!(bid = qbufcall(RD(q), size, BPRI_MED, rlmod_buffer, q))) {
13357c478bd9Sstevel@tonic-gate 		tid = qtimeout(RD(q), rlmod_timer, q, SIMWAIT);
13367c478bd9Sstevel@tonic-gate 		if (q->q_flag & QREADR)
13377c478bd9Sstevel@tonic-gate 			rmip->rtimoutid = tid;
13387c478bd9Sstevel@tonic-gate 		else
13397c478bd9Sstevel@tonic-gate 			rmip->wtimoutid = tid;
13407c478bd9Sstevel@tonic-gate 	} else	{
13417c478bd9Sstevel@tonic-gate 		if (q->q_flag & QREADR)
13427c478bd9Sstevel@tonic-gate 			rmip->rbufcid = bid;
13437c478bd9Sstevel@tonic-gate 		else
13447c478bd9Sstevel@tonic-gate 			rmip->wbufcid = bid;
13457c478bd9Sstevel@tonic-gate 	}
13467c478bd9Sstevel@tonic-gate }
1347