xref: /illumos-gate/usr/src/uts/common/io/logindmux.c (revision 19397407)
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
5*19397407SSherry Moore  * Common Development and Distribution License (the "License").
6*19397407SSherry Moore  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*19397407SSherry Moore  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate /*
287c478bd9Sstevel@tonic-gate  * Description: logindmux.c
297c478bd9Sstevel@tonic-gate  *
307c478bd9Sstevel@tonic-gate  * The logindmux driver is used with login modules (like telmod/rlmod).
317c478bd9Sstevel@tonic-gate  * This is a 1x1 cloning mux and two of these muxes are used. The lower link
327c478bd9Sstevel@tonic-gate  * of one of the muxes receives input from net and the lower link of the
337c478bd9Sstevel@tonic-gate  * other mux receives input from pseudo terminal subsystem.
347c478bd9Sstevel@tonic-gate  *
357c478bd9Sstevel@tonic-gate  * The logdmux_qexch_lock mutex manages the race between LOGDMX_IOC_QEXCHANGE,
367c478bd9Sstevel@tonic-gate  * logdmuxunlink() and logdmuxclose(), so that the instance selected as a peer
377c478bd9Sstevel@tonic-gate  * in LOGDMX_IOC_QEXCHANGE cannot be unlinked or closed until the qexchange
387c478bd9Sstevel@tonic-gate  * is complete; see the inline comments in the code for details.
397c478bd9Sstevel@tonic-gate  *
407c478bd9Sstevel@tonic-gate  * The logdmux_peerq_lock mutex manages the race between logdmuxlwsrv() and
417c478bd9Sstevel@tonic-gate  * logdmuxlrput() (when null'ing tmxp->peerq during LOGDMUX_UNLINK_REQ
427c478bd9Sstevel@tonic-gate  * processing).
437c478bd9Sstevel@tonic-gate  *
447c478bd9Sstevel@tonic-gate  * The logdmux_minor_lock mutex serializes the growth of logdmux_minor_arena
457c478bd9Sstevel@tonic-gate  * (the arena is grown gradually rather than allocated all at once so that
467c478bd9Sstevel@tonic-gate  * minor numbers are recycled sooner; for simplicity it is never shrunk).
477c478bd9Sstevel@tonic-gate  *
487c478bd9Sstevel@tonic-gate  * The unlink operation is implemented using protocol messages that flow
497c478bd9Sstevel@tonic-gate  * between the two logindmux peer instances. The instance processing the
507c478bd9Sstevel@tonic-gate  * I_UNLINK ioctl will send a LOGDMUX_UNLINK_REQ protocol message to its
517c478bd9Sstevel@tonic-gate  * peer to indicate that it wishes to unlink; the peer will process this
527c478bd9Sstevel@tonic-gate  * message in its lrput, null its tmxp->peerq and then send a
537c478bd9Sstevel@tonic-gate  * LOGDMUX_UNLINK_RESP protocol message in reply to indicate that the
547c478bd9Sstevel@tonic-gate  * unlink can proceed; having received the reply in its lrput, the
557c478bd9Sstevel@tonic-gate  * instance processing the I_UNLINK can then continue. To ensure that only
567c478bd9Sstevel@tonic-gate  * one of the peer instances will be actively processing an I_UNLINK at
577c478bd9Sstevel@tonic-gate  * any one time, a single structure (an unlinkinfo_t containing a mutex,
587c478bd9Sstevel@tonic-gate  * state variable and pointer to an M_CTL mblk) is allocated during
597c478bd9Sstevel@tonic-gate  * the processing of the LOGDMX_IOC_QEXCHANGE ioctl. The two instances, if
607c478bd9Sstevel@tonic-gate  * trying to unlink simultaneously, will race to get control of this
617c478bd9Sstevel@tonic-gate  * structure which contains the resources necessary to process the
627c478bd9Sstevel@tonic-gate  * I_UNLINK. The instance that wins this race will be able to continue
637c478bd9Sstevel@tonic-gate  * with the unlink whilst the other instance will be obliged to wait.
647c478bd9Sstevel@tonic-gate  */
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate #include <sys/types.h>
677c478bd9Sstevel@tonic-gate #include <sys/param.h>
687c478bd9Sstevel@tonic-gate #include <sys/errno.h>
697c478bd9Sstevel@tonic-gate #include <sys/debug.h>
707c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
717c478bd9Sstevel@tonic-gate #include <sys/stream.h>
727c478bd9Sstevel@tonic-gate #include <sys/logindmux.h>
737c478bd9Sstevel@tonic-gate #include <sys/logindmux_impl.h>
747c478bd9Sstevel@tonic-gate #include <sys/stat.h>
757c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
767c478bd9Sstevel@tonic-gate #include <sys/vmem.h>
777c478bd9Sstevel@tonic-gate #include <sys/strsun.h>
787c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
797c478bd9Sstevel@tonic-gate #include <sys/mkdev.h>
807c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
817c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
827c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
837c478bd9Sstevel@tonic-gate #include <sys/termios.h>
847c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
857c478bd9Sstevel@tonic-gate 
867c478bd9Sstevel@tonic-gate static int logdmuxopen(queue_t *, dev_t *, int, int, cred_t *);
877c478bd9Sstevel@tonic-gate static int logdmuxclose(queue_t *, int, cred_t *);
887c478bd9Sstevel@tonic-gate static int logdmuxursrv(queue_t *);
897c478bd9Sstevel@tonic-gate static int logdmuxuwput(queue_t *, mblk_t *);
907c478bd9Sstevel@tonic-gate static int logdmuxlrput(queue_t *, mblk_t *);
917c478bd9Sstevel@tonic-gate static int logdmuxlrsrv(queue_t *);
927c478bd9Sstevel@tonic-gate static int logdmuxlwsrv(queue_t *);
937c478bd9Sstevel@tonic-gate static int logdmuxuwsrv(queue_t *);
947c478bd9Sstevel@tonic-gate static int logdmux_alloc_unlinkinfo(struct tmx *, struct tmx *);
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate static void logdmuxlink(queue_t *, mblk_t *);
977c478bd9Sstevel@tonic-gate static void logdmuxunlink(queue_t *, mblk_t *);
987c478bd9Sstevel@tonic-gate static void logdmux_finish_unlink(queue_t *, mblk_t *);
997c478bd9Sstevel@tonic-gate static void logdmux_unlink_timer(void *arg);
1007c478bd9Sstevel@tonic-gate static void recover(queue_t *, mblk_t *, size_t);
1017c478bd9Sstevel@tonic-gate static void flushq_dataonly(queue_t *);
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate static kmutex_t logdmux_qexch_lock;
1047c478bd9Sstevel@tonic-gate static kmutex_t logdmux_peerq_lock;
1057c478bd9Sstevel@tonic-gate static kmutex_t logdmux_minor_lock;
1067c478bd9Sstevel@tonic-gate static minor_t	logdmux_maxminor = 256;	/* grown as necessary */
1077c478bd9Sstevel@tonic-gate static vmem_t	*logdmux_minor_arena;
1087c478bd9Sstevel@tonic-gate static void	*logdmux_statep;
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate static struct module_info logdmuxm_info = {
1117c478bd9Sstevel@tonic-gate 	LOGDMX_ID,
1127c478bd9Sstevel@tonic-gate 	"logindmux",
1137c478bd9Sstevel@tonic-gate 	0,
1147c478bd9Sstevel@tonic-gate 	256,
1157c478bd9Sstevel@tonic-gate 	512,
1167c478bd9Sstevel@tonic-gate 	256
1177c478bd9Sstevel@tonic-gate };
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate static struct qinit logdmuxurinit = {
1207c478bd9Sstevel@tonic-gate 	NULL,
1217c478bd9Sstevel@tonic-gate 	logdmuxursrv,
1227c478bd9Sstevel@tonic-gate 	logdmuxopen,
1237c478bd9Sstevel@tonic-gate 	logdmuxclose,
1247c478bd9Sstevel@tonic-gate 	NULL,
1257c478bd9Sstevel@tonic-gate 	&logdmuxm_info
1267c478bd9Sstevel@tonic-gate };
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate static struct qinit logdmuxuwinit = {
1297c478bd9Sstevel@tonic-gate 	logdmuxuwput,
1307c478bd9Sstevel@tonic-gate 	logdmuxuwsrv,
1317c478bd9Sstevel@tonic-gate 	NULL,
1327c478bd9Sstevel@tonic-gate 	NULL,
1337c478bd9Sstevel@tonic-gate 	NULL,
1347c478bd9Sstevel@tonic-gate 	&logdmuxm_info
1357c478bd9Sstevel@tonic-gate };
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate static struct qinit logdmuxlrinit = {
1387c478bd9Sstevel@tonic-gate 	logdmuxlrput,
1397c478bd9Sstevel@tonic-gate 	logdmuxlrsrv,
1407c478bd9Sstevel@tonic-gate 	NULL,
1417c478bd9Sstevel@tonic-gate 	NULL,
1427c478bd9Sstevel@tonic-gate 	NULL,
1437c478bd9Sstevel@tonic-gate 	&logdmuxm_info
1447c478bd9Sstevel@tonic-gate };
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate static struct qinit logdmuxlwinit = {
1477c478bd9Sstevel@tonic-gate 	NULL,
1487c478bd9Sstevel@tonic-gate 	logdmuxlwsrv,
1497c478bd9Sstevel@tonic-gate 	NULL,
1507c478bd9Sstevel@tonic-gate 	NULL,
1517c478bd9Sstevel@tonic-gate 	NULL,
1527c478bd9Sstevel@tonic-gate 	&logdmuxm_info
1537c478bd9Sstevel@tonic-gate };
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate struct streamtab logdmuxinfo = {
1567c478bd9Sstevel@tonic-gate 	&logdmuxurinit,
1577c478bd9Sstevel@tonic-gate 	&logdmuxuwinit,
1587c478bd9Sstevel@tonic-gate 	&logdmuxlrinit,
1597c478bd9Sstevel@tonic-gate 	&logdmuxlwinit
1607c478bd9Sstevel@tonic-gate };
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate static int logdmux_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
1637c478bd9Sstevel@tonic-gate static int logdmux_attach(dev_info_t *, ddi_attach_cmd_t);
1647c478bd9Sstevel@tonic-gate static int logdmux_detach(dev_info_t *, ddi_detach_cmd_t);
1657c478bd9Sstevel@tonic-gate static dev_info_t *logdmux_dip;
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate DDI_DEFINE_STREAM_OPS(logdmux_ops, nulldev, nulldev, logdmux_attach,
168*19397407SSherry Moore     logdmux_detach, nulldev, logdmux_info, D_MP | D_MTPERQ, &logdmuxinfo,
169*19397407SSherry Moore     ddi_quiesce_not_needed);
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate static struct modldrv modldrv = {
1727c478bd9Sstevel@tonic-gate 	&mod_driverops,
173*19397407SSherry Moore 	"logindmux driver",
1747c478bd9Sstevel@tonic-gate 	&logdmux_ops
1757c478bd9Sstevel@tonic-gate };
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
1787c478bd9Sstevel@tonic-gate 	MODREV_1, &modldrv, NULL
1797c478bd9Sstevel@tonic-gate };
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate int
_init(void)1827c478bd9Sstevel@tonic-gate _init(void)
1837c478bd9Sstevel@tonic-gate {
1847c478bd9Sstevel@tonic-gate 	int	ret;
1857c478bd9Sstevel@tonic-gate 
1867c478bd9Sstevel@tonic-gate 	mutex_init(&logdmux_peerq_lock, NULL, MUTEX_DRIVER, NULL);
1877c478bd9Sstevel@tonic-gate 	mutex_init(&logdmux_qexch_lock, NULL, MUTEX_DRIVER, NULL);
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate 	if ((ret = mod_install(&modlinkage)) != 0) {
1907c478bd9Sstevel@tonic-gate 		mutex_destroy(&logdmux_peerq_lock);
1917c478bd9Sstevel@tonic-gate 		mutex_destroy(&logdmux_qexch_lock);
1927c478bd9Sstevel@tonic-gate 		return (ret);
1937c478bd9Sstevel@tonic-gate 	}
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate 	logdmux_minor_arena = vmem_create("logdmux_minor", (void *)1,
1967c478bd9Sstevel@tonic-gate 	    logdmux_maxminor, 1, NULL, NULL, NULL, 0,
1977c478bd9Sstevel@tonic-gate 	    VM_SLEEP | VMC_IDENTIFIER);
1987c478bd9Sstevel@tonic-gate 	(void) ddi_soft_state_init(&logdmux_statep, sizeof (struct tmx), 1);
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate 	return (0);
2017c478bd9Sstevel@tonic-gate }
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate int
_fini(void)2047c478bd9Sstevel@tonic-gate _fini(void)
2057c478bd9Sstevel@tonic-gate {
2067c478bd9Sstevel@tonic-gate 	int	ret;
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate 	if ((ret = mod_remove(&modlinkage)) == 0) {
2097c478bd9Sstevel@tonic-gate 		mutex_destroy(&logdmux_peerq_lock);
2107c478bd9Sstevel@tonic-gate 		mutex_destroy(&logdmux_qexch_lock);
2117c478bd9Sstevel@tonic-gate 		ddi_soft_state_fini(&logdmux_statep);
2127c478bd9Sstevel@tonic-gate 		vmem_destroy(logdmux_minor_arena);
2137c478bd9Sstevel@tonic-gate 		logdmux_minor_arena = NULL;
2147c478bd9Sstevel@tonic-gate 	}
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate 	return (ret);
2177c478bd9Sstevel@tonic-gate }
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate int
_info(struct modinfo * modinfop)2207c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
2217c478bd9Sstevel@tonic-gate {
2227c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
2237c478bd9Sstevel@tonic-gate }
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate static int
logdmux_attach(dev_info_t * devi,ddi_attach_cmd_t cmd)2267c478bd9Sstevel@tonic-gate logdmux_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
2277c478bd9Sstevel@tonic-gate {
2287c478bd9Sstevel@tonic-gate 	if (cmd != DDI_ATTACH)
2297c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
2307c478bd9Sstevel@tonic-gate 
2317c478bd9Sstevel@tonic-gate 	if (ddi_create_minor_node(devi, "logindmux", S_IFCHR, 0, DDI_PSEUDO,
2327c478bd9Sstevel@tonic-gate 	    CLONE_DEV) == DDI_FAILURE)
2337c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate 	logdmux_dip = devi;
2367c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
2377c478bd9Sstevel@tonic-gate }
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate static int
logdmux_detach(dev_info_t * devi,ddi_detach_cmd_t cmd)2407c478bd9Sstevel@tonic-gate logdmux_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
2417c478bd9Sstevel@tonic-gate {
2427c478bd9Sstevel@tonic-gate 	if (cmd != DDI_DETACH)
2437c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate 	ddi_remove_minor_node(devi, NULL);
2467c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
2477c478bd9Sstevel@tonic-gate }
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate /* ARGSUSED */
2507c478bd9Sstevel@tonic-gate static int
logdmux_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)2517c478bd9Sstevel@tonic-gate logdmux_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
2527c478bd9Sstevel@tonic-gate {
2537c478bd9Sstevel@tonic-gate 	int error;
2547c478bd9Sstevel@tonic-gate 
2557c478bd9Sstevel@tonic-gate 	switch (infocmd) {
2567c478bd9Sstevel@tonic-gate 	case DDI_INFO_DEVT2DEVINFO:
2577c478bd9Sstevel@tonic-gate 		if (logdmux_dip == NULL) {
2587c478bd9Sstevel@tonic-gate 			error = DDI_FAILURE;
2597c478bd9Sstevel@tonic-gate 		} else {
2607c478bd9Sstevel@tonic-gate 			*result = logdmux_dip;
2617c478bd9Sstevel@tonic-gate 			error = DDI_SUCCESS;
2627c478bd9Sstevel@tonic-gate 		}
2637c478bd9Sstevel@tonic-gate 		break;
2647c478bd9Sstevel@tonic-gate 	case DDI_INFO_DEVT2INSTANCE:
2657c478bd9Sstevel@tonic-gate 		*result = (void *)0;
2667c478bd9Sstevel@tonic-gate 		error = DDI_SUCCESS;
2677c478bd9Sstevel@tonic-gate 		break;
2687c478bd9Sstevel@tonic-gate 	default:
2697c478bd9Sstevel@tonic-gate 		error = DDI_FAILURE;
2707c478bd9Sstevel@tonic-gate 	}
2717c478bd9Sstevel@tonic-gate 	return (error);
2727c478bd9Sstevel@tonic-gate }
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate /*
2757c478bd9Sstevel@tonic-gate  * Logindmux open routine
2767c478bd9Sstevel@tonic-gate  */
2777c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2787c478bd9Sstevel@tonic-gate static int
logdmuxopen(queue_t * q,dev_t * devp,int flag,int sflag,cred_t * crp)2797c478bd9Sstevel@tonic-gate logdmuxopen(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *crp)
2807c478bd9Sstevel@tonic-gate {
2817c478bd9Sstevel@tonic-gate 	struct	tmx *tmxp;
2827c478bd9Sstevel@tonic-gate 	minor_t	minor, omaxminor;
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate 	if (sflag != CLONEOPEN)
2857c478bd9Sstevel@tonic-gate 		return (EINVAL);
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate 	mutex_enter(&logdmux_minor_lock);
2887c478bd9Sstevel@tonic-gate 	if (vmem_size(logdmux_minor_arena, VMEM_FREE) == 0) {
2897c478bd9Sstevel@tonic-gate 		/*
2907c478bd9Sstevel@tonic-gate 		 * The arena has been exhausted; grow by powers of two
2917c478bd9Sstevel@tonic-gate 		 * up to MAXMIN; bail if we've run out of minors.
2927c478bd9Sstevel@tonic-gate 		 */
2937c478bd9Sstevel@tonic-gate 		if (logdmux_maxminor == MAXMIN) {
2947c478bd9Sstevel@tonic-gate 			mutex_exit(&logdmux_minor_lock);
2957c478bd9Sstevel@tonic-gate 			return (ENOMEM);
2967c478bd9Sstevel@tonic-gate 		}
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate 		omaxminor = logdmux_maxminor;
2997c478bd9Sstevel@tonic-gate 		logdmux_maxminor = MIN(logdmux_maxminor << 1, MAXMIN);
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate 		(void) vmem_add(logdmux_minor_arena,
3027c478bd9Sstevel@tonic-gate 		    (void *)(uintptr_t)(omaxminor + 1),
3037c478bd9Sstevel@tonic-gate 		    logdmux_maxminor - omaxminor, VM_SLEEP);
3047c478bd9Sstevel@tonic-gate 	}
3057c478bd9Sstevel@tonic-gate 	minor = (minor_t)(uintptr_t)
3067c478bd9Sstevel@tonic-gate 	    vmem_alloc(logdmux_minor_arena, 1, VM_SLEEP);
3077c478bd9Sstevel@tonic-gate 	mutex_exit(&logdmux_minor_lock);
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate 	if (ddi_soft_state_zalloc(logdmux_statep, minor) == DDI_FAILURE) {
3107c478bd9Sstevel@tonic-gate 		vmem_free(logdmux_minor_arena, (void *)(uintptr_t)minor, 1);
3117c478bd9Sstevel@tonic-gate 		return (ENOMEM);
3127c478bd9Sstevel@tonic-gate 	}
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate 	tmxp = ddi_get_soft_state(logdmux_statep, minor);
3157c478bd9Sstevel@tonic-gate 	tmxp->rdq = q;
3167c478bd9Sstevel@tonic-gate 	tmxp->muxq = NULL;
3177c478bd9Sstevel@tonic-gate 	tmxp->peerq = NULL;
3187c478bd9Sstevel@tonic-gate 	tmxp->unlinkinfop = NULL;
3197c478bd9Sstevel@tonic-gate 	tmxp->dev0 = minor;
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate 	*devp = makedevice(getmajor(*devp), tmxp->dev0);
3227c478bd9Sstevel@tonic-gate 	q->q_ptr = tmxp;
3237c478bd9Sstevel@tonic-gate 	WR(q)->q_ptr = tmxp;
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate 	qprocson(q);
3267c478bd9Sstevel@tonic-gate 	return (0);
3277c478bd9Sstevel@tonic-gate }
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate /*
3307c478bd9Sstevel@tonic-gate  * Logindmux close routine gets called when telnet connection is closed
3317c478bd9Sstevel@tonic-gate  */
3327c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3337c478bd9Sstevel@tonic-gate static int
logdmuxclose(queue_t * q,int flag,cred_t * crp)3347c478bd9Sstevel@tonic-gate logdmuxclose(queue_t *q, int flag, cred_t *crp)
3357c478bd9Sstevel@tonic-gate {
3367c478bd9Sstevel@tonic-gate 	struct tmx	*tmxp = q->q_ptr;
3377c478bd9Sstevel@tonic-gate 	minor_t		minor = tmxp->dev0;
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate 	ASSERT(tmxp->muxq == NULL);
3407c478bd9Sstevel@tonic-gate 	ASSERT(tmxp->peerq == NULL);
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate 	qprocsoff(q);
3437c478bd9Sstevel@tonic-gate 	if (tmxp->wbufcid != 0) {
3447c478bd9Sstevel@tonic-gate 		qunbufcall(q, tmxp->wbufcid);
3457c478bd9Sstevel@tonic-gate 		tmxp->wbufcid = 0;
3467c478bd9Sstevel@tonic-gate 	}
3477c478bd9Sstevel@tonic-gate 	if (tmxp->rbufcid != 0) {
3487c478bd9Sstevel@tonic-gate 		qunbufcall(q, tmxp->rbufcid);
3497c478bd9Sstevel@tonic-gate 		tmxp->rbufcid = 0;
3507c478bd9Sstevel@tonic-gate 	}
3517c478bd9Sstevel@tonic-gate 	if (tmxp->rtimoutid != 0) {
3527c478bd9Sstevel@tonic-gate 		(void) quntimeout(q, tmxp->rtimoutid);
3537c478bd9Sstevel@tonic-gate 		tmxp->rtimoutid = 0;
3547c478bd9Sstevel@tonic-gate 	}
3557c478bd9Sstevel@tonic-gate 	if (tmxp->wtimoutid != 0) {
3567c478bd9Sstevel@tonic-gate 		(void) quntimeout(q, tmxp->wtimoutid);
3577c478bd9Sstevel@tonic-gate 		tmxp->wtimoutid = 0;
3587c478bd9Sstevel@tonic-gate 	}
3597c478bd9Sstevel@tonic-gate 	if (tmxp->utimoutid != 0) {
3607c478bd9Sstevel@tonic-gate 		(void) quntimeout(q, tmxp->utimoutid);
3617c478bd9Sstevel@tonic-gate 		tmxp->utimoutid = 0;
3627c478bd9Sstevel@tonic-gate 	}
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate 	/*
3657c478bd9Sstevel@tonic-gate 	 * Hold logdmux_qexch_lock to prevent another thread that might be
3667c478bd9Sstevel@tonic-gate 	 * in LOGDMX_IOC_QEXCHANGE from looking up our state while we're
3677c478bd9Sstevel@tonic-gate 	 * disposing of it.
3687c478bd9Sstevel@tonic-gate 	 */
3697c478bd9Sstevel@tonic-gate 	mutex_enter(&logdmux_qexch_lock);
3707c478bd9Sstevel@tonic-gate 	ddi_soft_state_free(logdmux_statep, minor);
3717c478bd9Sstevel@tonic-gate 	vmem_free(logdmux_minor_arena, (void *)(uintptr_t)minor, 1);
3727c478bd9Sstevel@tonic-gate 	mutex_exit(&logdmux_qexch_lock);
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate 	q->q_ptr = NULL;
3757c478bd9Sstevel@tonic-gate 	WR(q)->q_ptr = NULL;
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate 	return (0);
3787c478bd9Sstevel@tonic-gate }
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate /*
3817c478bd9Sstevel@tonic-gate  * Upper read service routine
3827c478bd9Sstevel@tonic-gate  */
3837c478bd9Sstevel@tonic-gate static int
logdmuxursrv(queue_t * q)3847c478bd9Sstevel@tonic-gate logdmuxursrv(queue_t *q)
3857c478bd9Sstevel@tonic-gate {
3867c478bd9Sstevel@tonic-gate 	struct tmx *tmxp = q->q_ptr;
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate 	if (tmxp->muxq != NULL)
3897c478bd9Sstevel@tonic-gate 		qenable(RD(tmxp->muxq));
3907c478bd9Sstevel@tonic-gate 	return (0);
3917c478bd9Sstevel@tonic-gate }
3927c478bd9Sstevel@tonic-gate 
3937c478bd9Sstevel@tonic-gate /*
3947c478bd9Sstevel@tonic-gate  * This routine gets called when telnet daemon sends data or ioctl messages
3957c478bd9Sstevel@tonic-gate  * to upper mux queue.
3967c478bd9Sstevel@tonic-gate  */
3977c478bd9Sstevel@tonic-gate static int
logdmuxuwput(queue_t * q,mblk_t * mp)3987c478bd9Sstevel@tonic-gate logdmuxuwput(queue_t *q, mblk_t *mp)
3997c478bd9Sstevel@tonic-gate {
4007c478bd9Sstevel@tonic-gate 	queue_t		*qp;
4017c478bd9Sstevel@tonic-gate 	mblk_t		*newmp;
4027c478bd9Sstevel@tonic-gate 	struct iocblk	*ioc;
4037c478bd9Sstevel@tonic-gate 	minor_t		minor;
4047c478bd9Sstevel@tonic-gate 	STRUCT_HANDLE(protocol_arg, protoh);
4057c478bd9Sstevel@tonic-gate 	struct tmx	*tmxp, *tmxpeerp;
4067c478bd9Sstevel@tonic-gate 	int		error;
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate 	tmxp = q->q_ptr;
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate 	case M_IOCTL:
4137c478bd9Sstevel@tonic-gate 		ASSERT(MBLKL(mp) == sizeof (struct iocblk));
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate 		ioc = (struct iocblk *)mp->b_rptr;
4167c478bd9Sstevel@tonic-gate 		switch (ioc->ioc_cmd) {
4177c478bd9Sstevel@tonic-gate 		/*
4187c478bd9Sstevel@tonic-gate 		 * This is a special ioctl which exchanges q info
4197c478bd9Sstevel@tonic-gate 		 * of the two peers, connected to netf and ptmx.
4207c478bd9Sstevel@tonic-gate 		 */
4217c478bd9Sstevel@tonic-gate 		case LOGDMX_IOC_QEXCHANGE:
4227c478bd9Sstevel@tonic-gate 			error = miocpullup(mp,
4237c478bd9Sstevel@tonic-gate 			    SIZEOF_STRUCT(protocol_arg, ioc->ioc_flag));
4247c478bd9Sstevel@tonic-gate 			if (error != 0) {
4257c478bd9Sstevel@tonic-gate 				miocnak(q, mp, 0, error);
4267c478bd9Sstevel@tonic-gate 				break;
4277c478bd9Sstevel@tonic-gate 			}
4287c478bd9Sstevel@tonic-gate 			STRUCT_SET_HANDLE(protoh, ioc->ioc_flag,
4297c478bd9Sstevel@tonic-gate 			    (struct protocol_arg *)mp->b_cont->b_rptr);
4307c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
4317c478bd9Sstevel@tonic-gate 			if ((ioc->ioc_flag & DATAMODEL_MASK) ==
4327c478bd9Sstevel@tonic-gate 			    DATAMODEL_ILP32) {
4337c478bd9Sstevel@tonic-gate 				minor = getminor(expldev(
4347c478bd9Sstevel@tonic-gate 				    STRUCT_FGET(protoh, dev)));
4357c478bd9Sstevel@tonic-gate 			} else
4367c478bd9Sstevel@tonic-gate #endif
4377c478bd9Sstevel@tonic-gate 			{
4387c478bd9Sstevel@tonic-gate 				minor = getminor(STRUCT_FGET(protoh, dev));
4397c478bd9Sstevel@tonic-gate 			}
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate 			/*
4427c478bd9Sstevel@tonic-gate 			 * The second argument to ddi_get_soft_state() is
4437c478bd9Sstevel@tonic-gate 			 * interpreted as an `int', so prohibit negative
4447c478bd9Sstevel@tonic-gate 			 * values.
4457c478bd9Sstevel@tonic-gate 			 */
4467c478bd9Sstevel@tonic-gate 			if ((int)minor < 0) {
4477c478bd9Sstevel@tonic-gate 				miocnak(q, mp, 0, EINVAL);
4487c478bd9Sstevel@tonic-gate 				break;
4497c478bd9Sstevel@tonic-gate 			}
4507c478bd9Sstevel@tonic-gate 
4517c478bd9Sstevel@tonic-gate 			/*
4527c478bd9Sstevel@tonic-gate 			 * We must hold logdmux_qexch_lock while looking up
4537c478bd9Sstevel@tonic-gate 			 * the proposed peer to prevent another thread from
4547c478bd9Sstevel@tonic-gate 			 * simultaneously I_UNLINKing or closing it.
4557c478bd9Sstevel@tonic-gate 			 */
4567c478bd9Sstevel@tonic-gate 			mutex_enter(&logdmux_qexch_lock);
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate 			/*
4597c478bd9Sstevel@tonic-gate 			 * For LOGDMX_IOC_QEXCHANGE to succeed, our peer must
4607c478bd9Sstevel@tonic-gate 			 * exist (and not be us), and both we and our peer
4617c478bd9Sstevel@tonic-gate 			 * must be I_LINKed (i.e., muxq must not be NULL) and
4627c478bd9Sstevel@tonic-gate 			 * not already have a peer.
4637c478bd9Sstevel@tonic-gate 			 */
4647c478bd9Sstevel@tonic-gate 			tmxpeerp = ddi_get_soft_state(logdmux_statep, minor);
4657c478bd9Sstevel@tonic-gate 			if (tmxpeerp == NULL || tmxpeerp == tmxp ||
4667c478bd9Sstevel@tonic-gate 			    tmxpeerp->muxq == NULL || tmxpeerp->peerq != NULL ||
4677c478bd9Sstevel@tonic-gate 			    tmxp->muxq == NULL || tmxp->peerq != NULL) {
4687c478bd9Sstevel@tonic-gate 				mutex_exit(&logdmux_qexch_lock);
4697c478bd9Sstevel@tonic-gate 				miocnak(q, mp, 0, EINVAL);
4707c478bd9Sstevel@tonic-gate 				break;
4717c478bd9Sstevel@tonic-gate 			}
4727c478bd9Sstevel@tonic-gate 
4737c478bd9Sstevel@tonic-gate 			/*
4747c478bd9Sstevel@tonic-gate 			 * If `flag' is set then exchange queues and assume
4757c478bd9Sstevel@tonic-gate 			 * tmxp refers to the ptmx stream.
4767c478bd9Sstevel@tonic-gate 			 */
4777c478bd9Sstevel@tonic-gate 			if (STRUCT_FGET(protoh, flag)) {
4787c478bd9Sstevel@tonic-gate 				/*
4797c478bd9Sstevel@tonic-gate 				 * Allocate and populate the structure we
4807c478bd9Sstevel@tonic-gate 				 * need when processing an I_UNLINK ioctl.
4817c478bd9Sstevel@tonic-gate 				 * Give both logindmux instances a pointer
4827c478bd9Sstevel@tonic-gate 				 * to it from their tmx structure.
4837c478bd9Sstevel@tonic-gate 				 */
4847c478bd9Sstevel@tonic-gate 				if ((error = logdmux_alloc_unlinkinfo(
4857c478bd9Sstevel@tonic-gate 				    tmxp, tmxpeerp)) != 0) {
4867c478bd9Sstevel@tonic-gate 					mutex_exit(&logdmux_qexch_lock);
4877c478bd9Sstevel@tonic-gate 					miocnak(q, mp, 0, error);
4887c478bd9Sstevel@tonic-gate 					break;
4897c478bd9Sstevel@tonic-gate 				}
4907c478bd9Sstevel@tonic-gate 				tmxp->peerq = tmxpeerp->muxq;
4917c478bd9Sstevel@tonic-gate 				tmxpeerp->peerq = tmxp->muxq;
4927c478bd9Sstevel@tonic-gate 				tmxp->isptm = B_TRUE;
4937c478bd9Sstevel@tonic-gate 			}
4947c478bd9Sstevel@tonic-gate 			mutex_exit(&logdmux_qexch_lock);
4957c478bd9Sstevel@tonic-gate 			miocack(q, mp, 0, 0);
4967c478bd9Sstevel@tonic-gate 			break;
4977c478bd9Sstevel@tonic-gate 
4987c478bd9Sstevel@tonic-gate 		case I_LINK:
4997c478bd9Sstevel@tonic-gate 			ASSERT(MBLKL(mp->b_cont) == sizeof (struct linkblk));
5007c478bd9Sstevel@tonic-gate 			logdmuxlink(q, mp);
5017c478bd9Sstevel@tonic-gate 			break;
5027c478bd9Sstevel@tonic-gate 
5037c478bd9Sstevel@tonic-gate 		case I_UNLINK:
5047c478bd9Sstevel@tonic-gate 			ASSERT(MBLKL(mp->b_cont) == sizeof (struct linkblk));
5057c478bd9Sstevel@tonic-gate 			logdmuxunlink(q, mp);
5067c478bd9Sstevel@tonic-gate 			break;
5077c478bd9Sstevel@tonic-gate 
5087c478bd9Sstevel@tonic-gate 		default:
5097c478bd9Sstevel@tonic-gate 			if (tmxp->muxq == NULL) {
5107c478bd9Sstevel@tonic-gate 				miocnak(q, mp, 0, EINVAL);
5117c478bd9Sstevel@tonic-gate 				return (0);
5127c478bd9Sstevel@tonic-gate 			}
5137c478bd9Sstevel@tonic-gate 			putnext(tmxp->muxq, mp);
5147c478bd9Sstevel@tonic-gate 			break;
5157c478bd9Sstevel@tonic-gate 		}
5167c478bd9Sstevel@tonic-gate 
5177c478bd9Sstevel@tonic-gate 		break;
5187c478bd9Sstevel@tonic-gate 
5197c478bd9Sstevel@tonic-gate 	case M_DATA:
5207c478bd9Sstevel@tonic-gate 		if (!tmxp->isptm) {
5217c478bd9Sstevel@tonic-gate 			if ((newmp = allocb(sizeof (char), BPRI_MED)) == NULL) {
5227c478bd9Sstevel@tonic-gate 				recover(q, mp, sizeof (char));
5237c478bd9Sstevel@tonic-gate 				return (0);
5247c478bd9Sstevel@tonic-gate 			}
5257c478bd9Sstevel@tonic-gate 			newmp->b_datap->db_type = M_CTL;
5267c478bd9Sstevel@tonic-gate 			*newmp->b_wptr++ = M_CTL_MAGIC_NUMBER;
5277c478bd9Sstevel@tonic-gate 			newmp->b_cont = mp;
5287c478bd9Sstevel@tonic-gate 			mp = newmp;
5297c478bd9Sstevel@tonic-gate 		}
5307c478bd9Sstevel@tonic-gate 		/* FALLTHRU */
5317c478bd9Sstevel@tonic-gate 
5327c478bd9Sstevel@tonic-gate 	case M_PROTO:
5337c478bd9Sstevel@tonic-gate 	case M_PCPROTO:
5347c478bd9Sstevel@tonic-gate 		qp = tmxp->muxq;
5357c478bd9Sstevel@tonic-gate 		if (qp == NULL) {
5367c478bd9Sstevel@tonic-gate 			merror(q, mp, EINVAL);
5377c478bd9Sstevel@tonic-gate 			return (0);
5387c478bd9Sstevel@tonic-gate 		}
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate 		if (queclass(mp) < QPCTL) {
5417c478bd9Sstevel@tonic-gate 			if (q->q_first != NULL || !canputnext(qp)) {
5427c478bd9Sstevel@tonic-gate 				(void) putq(q, mp);
5437c478bd9Sstevel@tonic-gate 				return (0);
5447c478bd9Sstevel@tonic-gate 			}
5457c478bd9Sstevel@tonic-gate 		}
5467c478bd9Sstevel@tonic-gate 		putnext(qp, mp);
5477c478bd9Sstevel@tonic-gate 		break;
5487c478bd9Sstevel@tonic-gate 
5497c478bd9Sstevel@tonic-gate 	case M_FLUSH:
5507c478bd9Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHW)
5517c478bd9Sstevel@tonic-gate 			flushq(q, FLUSHALL);
5527c478bd9Sstevel@tonic-gate 
5537c478bd9Sstevel@tonic-gate 		if (tmxp->muxq != NULL) {
5547c478bd9Sstevel@tonic-gate 			putnext(tmxp->muxq, mp);
5557c478bd9Sstevel@tonic-gate 			return (0);
5567c478bd9Sstevel@tonic-gate 		}
5577c478bd9Sstevel@tonic-gate 
5587c478bd9Sstevel@tonic-gate 		*mp->b_rptr &= ~FLUSHW;
5597c478bd9Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHR)
5607c478bd9Sstevel@tonic-gate 			qreply(q, mp);
5617c478bd9Sstevel@tonic-gate 		else
5627c478bd9Sstevel@tonic-gate 			freemsg(mp);
5637c478bd9Sstevel@tonic-gate 		break;
5647c478bd9Sstevel@tonic-gate 
5657c478bd9Sstevel@tonic-gate 	default:
5667c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "logdmuxuwput: received unexpected message"
5677c478bd9Sstevel@tonic-gate 		    " of type 0x%x", mp->b_datap->db_type);
5687c478bd9Sstevel@tonic-gate 		freemsg(mp);
5697c478bd9Sstevel@tonic-gate 	}
5707c478bd9Sstevel@tonic-gate 	return (0);
5717c478bd9Sstevel@tonic-gate }
5727c478bd9Sstevel@tonic-gate 
5737c478bd9Sstevel@tonic-gate /*
5747c478bd9Sstevel@tonic-gate  * Upper write service routine
5757c478bd9Sstevel@tonic-gate  */
5767c478bd9Sstevel@tonic-gate static int
logdmuxuwsrv(queue_t * q)5777c478bd9Sstevel@tonic-gate logdmuxuwsrv(queue_t *q)
5787c478bd9Sstevel@tonic-gate {
5797c478bd9Sstevel@tonic-gate 	mblk_t		*mp, *newmp;
5807c478bd9Sstevel@tonic-gate 	queue_t		*qp;
5817c478bd9Sstevel@tonic-gate 	struct tmx	*tmxp = q->q_ptr;
5827c478bd9Sstevel@tonic-gate 
5837c478bd9Sstevel@tonic-gate 	while ((mp = getq(q)) != NULL) {
5847c478bd9Sstevel@tonic-gate 		switch (mp->b_datap->db_type) {
5857c478bd9Sstevel@tonic-gate 		case M_DATA:
5867c478bd9Sstevel@tonic-gate 			if (!tmxp->isptm) {
5877c478bd9Sstevel@tonic-gate 				if ((newmp = allocb(sizeof (char), BPRI_MED)) ==
5887c478bd9Sstevel@tonic-gate 				    NULL) {
5897c478bd9Sstevel@tonic-gate 					recover(q, mp, sizeof (char));
5907c478bd9Sstevel@tonic-gate 					return (0);
5917c478bd9Sstevel@tonic-gate 				}
5927c478bd9Sstevel@tonic-gate 				newmp->b_datap->db_type = M_CTL;
5937c478bd9Sstevel@tonic-gate 				*newmp->b_wptr++ = M_CTL_MAGIC_NUMBER;
5947c478bd9Sstevel@tonic-gate 				newmp->b_cont = mp;
5957c478bd9Sstevel@tonic-gate 				mp = newmp;
5967c478bd9Sstevel@tonic-gate 			}
5977c478bd9Sstevel@tonic-gate 			/* FALLTHRU */
5987c478bd9Sstevel@tonic-gate 
5997c478bd9Sstevel@tonic-gate 		case M_CTL:
6007c478bd9Sstevel@tonic-gate 		case M_PROTO:
6017c478bd9Sstevel@tonic-gate 			if (tmxp->muxq == NULL) {
6027c478bd9Sstevel@tonic-gate 				merror(q, mp, EIO);
6037c478bd9Sstevel@tonic-gate 				break;
6047c478bd9Sstevel@tonic-gate 			}
6057c478bd9Sstevel@tonic-gate 			qp = tmxp->muxq;
6067c478bd9Sstevel@tonic-gate 			if (!canputnext(qp)) {
6077c478bd9Sstevel@tonic-gate 				(void) putbq(q, mp);
6087c478bd9Sstevel@tonic-gate 				return (0);
6097c478bd9Sstevel@tonic-gate 			}
6107c478bd9Sstevel@tonic-gate 			putnext(qp, mp);
6117c478bd9Sstevel@tonic-gate 			break;
6127c478bd9Sstevel@tonic-gate 
6137c478bd9Sstevel@tonic-gate 
6147c478bd9Sstevel@tonic-gate 		default:
6157c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE, "logdmuxuwsrv: received unexpected"
6167c478bd9Sstevel@tonic-gate 			    " message of type 0x%x", mp->b_datap->db_type);
6177c478bd9Sstevel@tonic-gate 			freemsg(mp);
6187c478bd9Sstevel@tonic-gate 		}
6197c478bd9Sstevel@tonic-gate 	}
6207c478bd9Sstevel@tonic-gate 	return (0);
6217c478bd9Sstevel@tonic-gate }
6227c478bd9Sstevel@tonic-gate 
6237c478bd9Sstevel@tonic-gate /*
6247c478bd9Sstevel@tonic-gate  * Logindmux lower put routine detects from which of the two lower queues
6257c478bd9Sstevel@tonic-gate  * the data needs to be read from and writes it out to its peer queue.
6267c478bd9Sstevel@tonic-gate  * For protocol, it detects M_CTL and sends its data to the daemon. Also,
6277c478bd9Sstevel@tonic-gate  * for ioctl and other types of messages, it lets the daemon handle it.
6287c478bd9Sstevel@tonic-gate  */
6297c478bd9Sstevel@tonic-gate static int
logdmuxlrput(queue_t * q,mblk_t * mp)6307c478bd9Sstevel@tonic-gate logdmuxlrput(queue_t *q, mblk_t *mp)
6317c478bd9Sstevel@tonic-gate {
6327c478bd9Sstevel@tonic-gate 	mblk_t		*savemp;
6337c478bd9Sstevel@tonic-gate 	queue_t 	*qp;
6347c478bd9Sstevel@tonic-gate 	struct iocblk	*ioc;
6357c478bd9Sstevel@tonic-gate 	struct tmx	*tmxp = q->q_ptr;
6367c478bd9Sstevel@tonic-gate 	uchar_t		flush;
6377c478bd9Sstevel@tonic-gate 	uint_t		*messagep;
6387c478bd9Sstevel@tonic-gate 	unlinkinfo_t	*unlinkinfop = tmxp->unlinkinfop;
6397c478bd9Sstevel@tonic-gate 
6407c478bd9Sstevel@tonic-gate 	if (tmxp->muxq == NULL || tmxp->peerq == NULL) {
6417c478bd9Sstevel@tonic-gate 		freemsg(mp);
6427c478bd9Sstevel@tonic-gate 		return (0);
6437c478bd9Sstevel@tonic-gate 	}
6447c478bd9Sstevel@tonic-gate 
6457c478bd9Sstevel@tonic-gate 	/*
6467c478bd9Sstevel@tonic-gate 	 * If there's already a message on our queue and the incoming
6477c478bd9Sstevel@tonic-gate 	 * message is not of a high-priority, enqueue the message --
6487c478bd9Sstevel@tonic-gate 	 * but not if it's a logindmux protocol message.
6497c478bd9Sstevel@tonic-gate 	 */
6507c478bd9Sstevel@tonic-gate 	if ((q->q_first != NULL) && (queclass(mp) < QPCTL) &&
6517c478bd9Sstevel@tonic-gate 	    (!LOGDMUX_PROTO_MBLK(mp))) {
6527c478bd9Sstevel@tonic-gate 		(void) putq(q, mp);
6537c478bd9Sstevel@tonic-gate 		return (0);
6547c478bd9Sstevel@tonic-gate 	}
6557c478bd9Sstevel@tonic-gate 
6567c478bd9Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
6577c478bd9Sstevel@tonic-gate 
6587c478bd9Sstevel@tonic-gate 	case M_IOCTL:
6597c478bd9Sstevel@tonic-gate 		ioc = (struct iocblk *)mp->b_rptr;
6607c478bd9Sstevel@tonic-gate 		switch (ioc->ioc_cmd) {
6617c478bd9Sstevel@tonic-gate 
6627c478bd9Sstevel@tonic-gate 		case TIOCSWINSZ:
6637c478bd9Sstevel@tonic-gate 		case TCSETAF:
6647c478bd9Sstevel@tonic-gate 		case TCSETSF:
6657c478bd9Sstevel@tonic-gate 		case TCSETA:
6667c478bd9Sstevel@tonic-gate 		case TCSETAW:
6677c478bd9Sstevel@tonic-gate 		case TCSETS:
6687c478bd9Sstevel@tonic-gate 		case TCSETSW:
6697c478bd9Sstevel@tonic-gate 		case TCSBRK:
6707c478bd9Sstevel@tonic-gate 		case TIOCSTI:
6717c478bd9Sstevel@tonic-gate 			qp = tmxp->peerq;
6727c478bd9Sstevel@tonic-gate 			break;
6737c478bd9Sstevel@tonic-gate 
6747c478bd9Sstevel@tonic-gate 		default:
6757c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE, "logdmuxlrput: received unexpected"
6767c478bd9Sstevel@tonic-gate 			    " request for ioctl 0x%x", ioc->ioc_cmd);
6777c478bd9Sstevel@tonic-gate 
6787c478bd9Sstevel@tonic-gate 			/* NAK unrecognized ioctl's. */
6797c478bd9Sstevel@tonic-gate 			miocnak(q, mp, 0, 0);
6807c478bd9Sstevel@tonic-gate 			return (0);
6817c478bd9Sstevel@tonic-gate 		}
6827c478bd9Sstevel@tonic-gate 		break;
6837c478bd9Sstevel@tonic-gate 
6847c478bd9Sstevel@tonic-gate 	case M_DATA:
6857c478bd9Sstevel@tonic-gate 	case M_HANGUP:
6867c478bd9Sstevel@tonic-gate 		qp = tmxp->peerq;
6877c478bd9Sstevel@tonic-gate 		break;
6887c478bd9Sstevel@tonic-gate 
6897c478bd9Sstevel@tonic-gate 	case M_CTL:
6907c478bd9Sstevel@tonic-gate 		/*
6917c478bd9Sstevel@tonic-gate 		 * The protocol messages that flow between the peers
6927c478bd9Sstevel@tonic-gate 		 * to implement the unlink functionality are M_CTLs
6937c478bd9Sstevel@tonic-gate 		 * which have the M_IOCTL/I_UNLINK mblk of the ioctl
6947c478bd9Sstevel@tonic-gate 		 * attached via b_cont.  LOGDMUX_PROTO_MBLK() uses
6957c478bd9Sstevel@tonic-gate 		 * this to determine whether a particular M_CTL is a
6967c478bd9Sstevel@tonic-gate 		 * peer protocol message.
6977c478bd9Sstevel@tonic-gate 		 */
6987c478bd9Sstevel@tonic-gate 		if (LOGDMUX_PROTO_MBLK(mp)) {
6997c478bd9Sstevel@tonic-gate 			messagep = (uint_t *)mp->b_rptr;
7007c478bd9Sstevel@tonic-gate 
7017c478bd9Sstevel@tonic-gate 			switch (*messagep) {
7027c478bd9Sstevel@tonic-gate 
7037c478bd9Sstevel@tonic-gate 			case LOGDMUX_UNLINK_REQ:
7047c478bd9Sstevel@tonic-gate 				/*
7057c478bd9Sstevel@tonic-gate 				 * We've received a message from our
7067c478bd9Sstevel@tonic-gate 				 * peer indicating that it wants to
7077c478bd9Sstevel@tonic-gate 				 * unlink.
7087c478bd9Sstevel@tonic-gate 				 */
7097c478bd9Sstevel@tonic-gate 				*messagep = LOGDMUX_UNLINK_RESP;
7107c478bd9Sstevel@tonic-gate 				qp = tmxp->peerq;
7117c478bd9Sstevel@tonic-gate 
7127c478bd9Sstevel@tonic-gate 				mutex_enter(&logdmux_peerq_lock);
7137c478bd9Sstevel@tonic-gate 				tmxp->peerq = NULL;
7147c478bd9Sstevel@tonic-gate 				mutex_exit(&logdmux_peerq_lock);
7157c478bd9Sstevel@tonic-gate 
7167c478bd9Sstevel@tonic-gate 				put(RD(qp), mp);
7177c478bd9Sstevel@tonic-gate 				return (0);
7187c478bd9Sstevel@tonic-gate 
7197c478bd9Sstevel@tonic-gate 			case LOGDMUX_UNLINK_RESP:
7207c478bd9Sstevel@tonic-gate 				/*
7217c478bd9Sstevel@tonic-gate 				 * We've received a positive response
7227c478bd9Sstevel@tonic-gate 				 * from our peer to an earlier
7237c478bd9Sstevel@tonic-gate 				 * LOGDMUX_UNLINK_REQ that we sent.
7247c478bd9Sstevel@tonic-gate 				 * We can now carry on with the unlink.
7257c478bd9Sstevel@tonic-gate 				 */
7267c478bd9Sstevel@tonic-gate 				qp = tmxp->rdq;
7277c478bd9Sstevel@tonic-gate 				mutex_enter(&unlinkinfop->state_lock);
7287c478bd9Sstevel@tonic-gate 				ASSERT(unlinkinfop->state ==
7297c478bd9Sstevel@tonic-gate 				    LOGDMUX_UNLINK_PENDING);
7307c478bd9Sstevel@tonic-gate 				unlinkinfop->state = LOGDMUX_UNLINKED;
7317c478bd9Sstevel@tonic-gate 				mutex_exit(&unlinkinfop->state_lock);
7327c478bd9Sstevel@tonic-gate 				logdmux_finish_unlink(WR(qp), mp->b_cont);
7337c478bd9Sstevel@tonic-gate 				return (0);
7347c478bd9Sstevel@tonic-gate 			}
7357c478bd9Sstevel@tonic-gate 		}
7367c478bd9Sstevel@tonic-gate 
7377c478bd9Sstevel@tonic-gate 		qp = tmxp->rdq;
7387c478bd9Sstevel@tonic-gate 		if (q->q_first != NULL || !canputnext(qp)) {
7397c478bd9Sstevel@tonic-gate 			(void) putq(q, mp);
7407c478bd9Sstevel@tonic-gate 			return (0);
7417c478bd9Sstevel@tonic-gate 		}
7427c478bd9Sstevel@tonic-gate 		if ((MBLKL(mp) == 1) && (*mp->b_rptr == M_CTL_MAGIC_NUMBER)) {
7437c478bd9Sstevel@tonic-gate 			savemp = mp->b_cont;
7447c478bd9Sstevel@tonic-gate 			freeb(mp);
7457c478bd9Sstevel@tonic-gate 			mp = savemp;
7467c478bd9Sstevel@tonic-gate 		}
7477c478bd9Sstevel@tonic-gate 		putnext(qp, mp);
7487c478bd9Sstevel@tonic-gate 		return (0);
7497c478bd9Sstevel@tonic-gate 
7507c478bd9Sstevel@tonic-gate 	case M_IOCACK:
7517c478bd9Sstevel@tonic-gate 	case M_IOCNAK:
7527c478bd9Sstevel@tonic-gate 	case M_PROTO:
7537c478bd9Sstevel@tonic-gate 	case M_PCPROTO:
7547c478bd9Sstevel@tonic-gate 	case M_PCSIG:
7557c478bd9Sstevel@tonic-gate 	case M_SETOPTS:
7567c478bd9Sstevel@tonic-gate 		qp = tmxp->rdq;
7577c478bd9Sstevel@tonic-gate 		break;
7587c478bd9Sstevel@tonic-gate 
7597c478bd9Sstevel@tonic-gate 	case M_ERROR:
7607c478bd9Sstevel@tonic-gate 		if (tmxp->isptm) {
7617c478bd9Sstevel@tonic-gate 			/*
7627c478bd9Sstevel@tonic-gate 			 * This error is from ptm.  We could tell TCP to
7637c478bd9Sstevel@tonic-gate 			 * shutdown the connection, but it's easier to just
7647c478bd9Sstevel@tonic-gate 			 * wait for the daemon to get SIGCHLD and close from
7657c478bd9Sstevel@tonic-gate 			 * above.
7667c478bd9Sstevel@tonic-gate 			 */
7677c478bd9Sstevel@tonic-gate 			freemsg(mp);
7687c478bd9Sstevel@tonic-gate 			return (0);
7697c478bd9Sstevel@tonic-gate 		}
7707c478bd9Sstevel@tonic-gate 		/*
7717c478bd9Sstevel@tonic-gate 		 * This is from TCP.  Don't really know why we'd
7727c478bd9Sstevel@tonic-gate 		 * get this, but we have a pretty good idea what
7737c478bd9Sstevel@tonic-gate 		 * to do:  Send M_HANGUP to the pty.
7747c478bd9Sstevel@tonic-gate 		 */
7757c478bd9Sstevel@tonic-gate 		mp->b_datap->db_type = M_HANGUP;
7767c478bd9Sstevel@tonic-gate 		mp->b_wptr = mp->b_rptr;
7777c478bd9Sstevel@tonic-gate 		qp = tmxp->peerq;
7787c478bd9Sstevel@tonic-gate 		break;
7797c478bd9Sstevel@tonic-gate 
7807c478bd9Sstevel@tonic-gate 	case M_FLUSH:
7817c478bd9Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHR)
7827c478bd9Sstevel@tonic-gate 			flushq_dataonly(q);
7837c478bd9Sstevel@tonic-gate 
7847c478bd9Sstevel@tonic-gate 		if (mp->b_flag & MSGMARK) {
7857c478bd9Sstevel@tonic-gate 			/*
7867c478bd9Sstevel@tonic-gate 			 * This M_FLUSH has been marked by the module
7877c478bd9Sstevel@tonic-gate 			 * below as intended for the upper queue,
7887c478bd9Sstevel@tonic-gate 			 * not the peer queue.
7897c478bd9Sstevel@tonic-gate 			 */
7907c478bd9Sstevel@tonic-gate 			qp = tmxp->rdq;
7917c478bd9Sstevel@tonic-gate 			mp->b_flag &= ~MSGMARK;
7927c478bd9Sstevel@tonic-gate 		} else {
7937c478bd9Sstevel@tonic-gate 			/*
7947c478bd9Sstevel@tonic-gate 			 * Wrap this M_FLUSH through the mux.
7957c478bd9Sstevel@tonic-gate 			 * The FLUSHR and FLUSHW bits must be
7967c478bd9Sstevel@tonic-gate 			 * reversed.
7977c478bd9Sstevel@tonic-gate 			 */
7987c478bd9Sstevel@tonic-gate 			qp = tmxp->peerq;
7997c478bd9Sstevel@tonic-gate 			flush = *mp->b_rptr;
8007c478bd9Sstevel@tonic-gate 			*mp->b_rptr &= ~(FLUSHR | FLUSHW);
8017c478bd9Sstevel@tonic-gate 			if (flush & FLUSHW)
8027c478bd9Sstevel@tonic-gate 				*mp->b_rptr |= FLUSHR;
8037c478bd9Sstevel@tonic-gate 			if (flush & FLUSHR)
8047c478bd9Sstevel@tonic-gate 				*mp->b_rptr |= FLUSHW;
8057c478bd9Sstevel@tonic-gate 		}
8067c478bd9Sstevel@tonic-gate 		break;
8077c478bd9Sstevel@tonic-gate 
8087c478bd9Sstevel@tonic-gate 	case M_START:
8097c478bd9Sstevel@tonic-gate 	case M_STOP:
8107c478bd9Sstevel@tonic-gate 	case M_STARTI:
8117c478bd9Sstevel@tonic-gate 	case M_STOPI:
8127c478bd9Sstevel@tonic-gate 		freemsg(mp);
8137c478bd9Sstevel@tonic-gate 		return (0);
8147c478bd9Sstevel@tonic-gate 
8157c478bd9Sstevel@tonic-gate 	default:
8167c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "logdmuxlrput: received unexpected "
8177c478bd9Sstevel@tonic-gate 		    "message of type 0x%x", mp->b_datap->db_type);
8187c478bd9Sstevel@tonic-gate 		freemsg(mp);
8197c478bd9Sstevel@tonic-gate 		return (0);
8207c478bd9Sstevel@tonic-gate 	}
8217c478bd9Sstevel@tonic-gate 	if (queclass(mp) < QPCTL) {
8227c478bd9Sstevel@tonic-gate 		if (q->q_first != NULL || !canputnext(qp)) {
8237c478bd9Sstevel@tonic-gate 			(void) putq(q, mp);
8247c478bd9Sstevel@tonic-gate 			return (0);
8257c478bd9Sstevel@tonic-gate 		}
8267c478bd9Sstevel@tonic-gate 	}
8277c478bd9Sstevel@tonic-gate 	putnext(qp, mp);
8287c478bd9Sstevel@tonic-gate 	return (0);
8297c478bd9Sstevel@tonic-gate }
8307c478bd9Sstevel@tonic-gate 
8317c478bd9Sstevel@tonic-gate /*
8327c478bd9Sstevel@tonic-gate  * Lower read service routine
8337c478bd9Sstevel@tonic-gate  */
8347c478bd9Sstevel@tonic-gate static int
logdmuxlrsrv(queue_t * q)8357c478bd9Sstevel@tonic-gate logdmuxlrsrv(queue_t *q)
8367c478bd9Sstevel@tonic-gate {
8377c478bd9Sstevel@tonic-gate 	mblk_t		*mp, *savemp;
8387c478bd9Sstevel@tonic-gate 	queue_t 	*qp;
8397c478bd9Sstevel@tonic-gate 	struct iocblk	*ioc;
8407c478bd9Sstevel@tonic-gate 	struct tmx	*tmxp = q->q_ptr;
8417c478bd9Sstevel@tonic-gate 
8427c478bd9Sstevel@tonic-gate 	while ((mp = getq(q)) != NULL) {
8437c478bd9Sstevel@tonic-gate 		if (tmxp->muxq == NULL || tmxp->peerq == NULL) {
8447c478bd9Sstevel@tonic-gate 			freemsg(mp);
8457c478bd9Sstevel@tonic-gate 			continue;
8467c478bd9Sstevel@tonic-gate 		}
8477c478bd9Sstevel@tonic-gate 
8487c478bd9Sstevel@tonic-gate 		switch (mp->b_datap->db_type) {
8497c478bd9Sstevel@tonic-gate 
8507c478bd9Sstevel@tonic-gate 		case M_IOCTL:
8517c478bd9Sstevel@tonic-gate 			ioc = (struct iocblk *)mp->b_rptr;
8527c478bd9Sstevel@tonic-gate 
8537c478bd9Sstevel@tonic-gate 			switch (ioc->ioc_cmd) {
8547c478bd9Sstevel@tonic-gate 
8557c478bd9Sstevel@tonic-gate 			case TIOCSWINSZ:
8567c478bd9Sstevel@tonic-gate 			case TCSETAF:
8577c478bd9Sstevel@tonic-gate 			case TCSETSF:
8587c478bd9Sstevel@tonic-gate 			case TCSETA:
8597c478bd9Sstevel@tonic-gate 			case TCSETAW:
8607c478bd9Sstevel@tonic-gate 			case TCSETS:
8617c478bd9Sstevel@tonic-gate 			case TCSETSW:
8627c478bd9Sstevel@tonic-gate 			case TCSBRK:
8637c478bd9Sstevel@tonic-gate 			case TIOCSTI:
8647c478bd9Sstevel@tonic-gate 				qp = tmxp->peerq;
8657c478bd9Sstevel@tonic-gate 				break;
8667c478bd9Sstevel@tonic-gate 
8677c478bd9Sstevel@tonic-gate 			default:
8687c478bd9Sstevel@tonic-gate 				cmn_err(CE_NOTE, "logdmuxlrsrv: received "
8697c478bd9Sstevel@tonic-gate 				    "unexpected request for ioctl 0x%x",
8707c478bd9Sstevel@tonic-gate 				    ioc->ioc_cmd);
8717c478bd9Sstevel@tonic-gate 
8727c478bd9Sstevel@tonic-gate 				/* NAK unrecognized ioctl's. */
8737c478bd9Sstevel@tonic-gate 				miocnak(q, mp, 0, 0);
8747c478bd9Sstevel@tonic-gate 				continue;
8757c478bd9Sstevel@tonic-gate 			}
8767c478bd9Sstevel@tonic-gate 			break;
8777c478bd9Sstevel@tonic-gate 
8787c478bd9Sstevel@tonic-gate 		case M_DATA:
8797c478bd9Sstevel@tonic-gate 		case M_HANGUP:
8807c478bd9Sstevel@tonic-gate 			qp = tmxp->peerq;
8817c478bd9Sstevel@tonic-gate 			break;
8827c478bd9Sstevel@tonic-gate 
8837c478bd9Sstevel@tonic-gate 		case M_CTL:
8847c478bd9Sstevel@tonic-gate 			qp = tmxp->rdq;
8857c478bd9Sstevel@tonic-gate 			if (!canputnext(qp)) {
8867c478bd9Sstevel@tonic-gate 				(void) putbq(q, mp);
8877c478bd9Sstevel@tonic-gate 				return (0);
8887c478bd9Sstevel@tonic-gate 			}
8897c478bd9Sstevel@tonic-gate 			if (MBLKL(mp) == 1 &&
8907c478bd9Sstevel@tonic-gate 			    (*mp->b_rptr == M_CTL_MAGIC_NUMBER)) {
8917c478bd9Sstevel@tonic-gate 				savemp = mp->b_cont;
8927c478bd9Sstevel@tonic-gate 				freeb(mp);
8937c478bd9Sstevel@tonic-gate 				mp = savemp;
8947c478bd9Sstevel@tonic-gate 			}
8957c478bd9Sstevel@tonic-gate 			putnext(qp, mp);
8967c478bd9Sstevel@tonic-gate 			continue;
8977c478bd9Sstevel@tonic-gate 
8987c478bd9Sstevel@tonic-gate 		case M_PROTO:
8997c478bd9Sstevel@tonic-gate 		case M_SETOPTS:
9007c478bd9Sstevel@tonic-gate 			qp = tmxp->rdq;
9017c478bd9Sstevel@tonic-gate 			break;
9027c478bd9Sstevel@tonic-gate 
9037c478bd9Sstevel@tonic-gate 		default:
9047c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE, "logdmuxlrsrv: received unexpected "
9057c478bd9Sstevel@tonic-gate 			    "message of type 0x%x", mp->b_datap->db_type);
9067c478bd9Sstevel@tonic-gate 			freemsg(mp);
9077c478bd9Sstevel@tonic-gate 			continue;
9087c478bd9Sstevel@tonic-gate 		}
9097c478bd9Sstevel@tonic-gate 		ASSERT(queclass(mp) < QPCTL);
9107c478bd9Sstevel@tonic-gate 		if (!canputnext(qp)) {
9117c478bd9Sstevel@tonic-gate 			(void) putbq(q, mp);
9127c478bd9Sstevel@tonic-gate 			return (0);
9137c478bd9Sstevel@tonic-gate 		}
9147c478bd9Sstevel@tonic-gate 		putnext(qp, mp);
9157c478bd9Sstevel@tonic-gate 	}
9167c478bd9Sstevel@tonic-gate 	return (0);
9177c478bd9Sstevel@tonic-gate }
9187c478bd9Sstevel@tonic-gate 
9197c478bd9Sstevel@tonic-gate /*
9207c478bd9Sstevel@tonic-gate  * Lower side write service procedure.  No messages are ever placed on
9217c478bd9Sstevel@tonic-gate  * the write queue here, this just back-enables all of the upper side
9227c478bd9Sstevel@tonic-gate  * write service procedures.
9237c478bd9Sstevel@tonic-gate  */
9247c478bd9Sstevel@tonic-gate static int
logdmuxlwsrv(queue_t * q)9257c478bd9Sstevel@tonic-gate logdmuxlwsrv(queue_t *q)
9267c478bd9Sstevel@tonic-gate {
9277c478bd9Sstevel@tonic-gate 	struct tmx *tmxp = q->q_ptr;
9287c478bd9Sstevel@tonic-gate 
9297c478bd9Sstevel@tonic-gate 	/*
9307c478bd9Sstevel@tonic-gate 	 * Qenable upper write queue and find out which lower
9317c478bd9Sstevel@tonic-gate 	 * queue needs to be restarted with flow control.
9327c478bd9Sstevel@tonic-gate 	 * Qenable the peer queue so canputnext will
9337c478bd9Sstevel@tonic-gate 	 * succeed on next call to logdmuxlrput.
9347c478bd9Sstevel@tonic-gate 	 */
9357c478bd9Sstevel@tonic-gate 	qenable(WR(tmxp->rdq));
9367c478bd9Sstevel@tonic-gate 
9377c478bd9Sstevel@tonic-gate 	mutex_enter(&logdmux_peerq_lock);
9387c478bd9Sstevel@tonic-gate 	if (tmxp->peerq != NULL)
9397c478bd9Sstevel@tonic-gate 		qenable(RD(tmxp->peerq));
9407c478bd9Sstevel@tonic-gate 	mutex_exit(&logdmux_peerq_lock);
9417c478bd9Sstevel@tonic-gate 
9427c478bd9Sstevel@tonic-gate 	return (0);
9437c478bd9Sstevel@tonic-gate }
9447c478bd9Sstevel@tonic-gate 
9457c478bd9Sstevel@tonic-gate /*
9467c478bd9Sstevel@tonic-gate  * This routine does I_LINK operation.
9477c478bd9Sstevel@tonic-gate  */
9487c478bd9Sstevel@tonic-gate static void
logdmuxlink(queue_t * q,mblk_t * mp)9497c478bd9Sstevel@tonic-gate logdmuxlink(queue_t *q, mblk_t *mp)
9507c478bd9Sstevel@tonic-gate {
9517c478bd9Sstevel@tonic-gate 	struct tmx	*tmxp = q->q_ptr;
9527c478bd9Sstevel@tonic-gate 	struct linkblk	*lp = (struct linkblk *)mp->b_cont->b_rptr;
9537c478bd9Sstevel@tonic-gate 
9547c478bd9Sstevel@tonic-gate 	/*
9557c478bd9Sstevel@tonic-gate 	 * Fail if we're already linked.
9567c478bd9Sstevel@tonic-gate 	 */
9577c478bd9Sstevel@tonic-gate 	if (tmxp->muxq != NULL) {
9587c478bd9Sstevel@tonic-gate 		miocnak(q, mp, 0, EINVAL);
9597c478bd9Sstevel@tonic-gate 		return;
9607c478bd9Sstevel@tonic-gate 	}
9617c478bd9Sstevel@tonic-gate 
9627c478bd9Sstevel@tonic-gate 	tmxp->muxq = lp->l_qbot;
9637c478bd9Sstevel@tonic-gate 	tmxp->muxq->q_ptr = tmxp;
9647c478bd9Sstevel@tonic-gate 	RD(tmxp->muxq)->q_ptr = tmxp;
9657c478bd9Sstevel@tonic-gate 
9667c478bd9Sstevel@tonic-gate 	miocack(q, mp, 0, 0);
9677c478bd9Sstevel@tonic-gate }
9687c478bd9Sstevel@tonic-gate 
9697c478bd9Sstevel@tonic-gate /*
9707c478bd9Sstevel@tonic-gate  * logdmuxunlink() is called from logdmuxuwput() and is the first of two
9717c478bd9Sstevel@tonic-gate  * functions which process an I_UNLINK ioctl. logdmuxunlink() will determine
9727c478bd9Sstevel@tonic-gate  * the state of logindmux peer linkage and, based on this, control when the
9737c478bd9Sstevel@tonic-gate  * second function, logdmux_finish_unlink(), is called.  It's
9747c478bd9Sstevel@tonic-gate  * logdmux_finish_unlink() that's sending the M_IOCACK upstream and
9757c478bd9Sstevel@tonic-gate  * resetting the link state.
9767c478bd9Sstevel@tonic-gate  */
9777c478bd9Sstevel@tonic-gate static void
logdmuxunlink(queue_t * q,mblk_t * mp)9787c478bd9Sstevel@tonic-gate logdmuxunlink(queue_t *q, mblk_t *mp)
9797c478bd9Sstevel@tonic-gate {
9807c478bd9Sstevel@tonic-gate 	struct tmx	*tmxp = q->q_ptr;
9817c478bd9Sstevel@tonic-gate 	unlinkinfo_t	*unlinkinfop;
9827c478bd9Sstevel@tonic-gate 
9837c478bd9Sstevel@tonic-gate 	/*
9847c478bd9Sstevel@tonic-gate 	 * If we don't have a peer, just unlink.  Note that this check needs
9857c478bd9Sstevel@tonic-gate 	 * to be done under logdmux_qexch_lock to prevent racing with
9867c478bd9Sstevel@tonic-gate 	 * LOGDMX_IOC_QEXCHANGE, and we *must* set muxq to NULL prior to
9877c478bd9Sstevel@tonic-gate 	 * releasing the lock so that LOGDMX_IOC_QEXCHANGE will not consider
9887c478bd9Sstevel@tonic-gate 	 * us as a possible peer anymore (if it already considers us to be a
9897c478bd9Sstevel@tonic-gate 	 * peer, then unlinkinfop will not be NULL) -- NULLing muxq precludes
9907c478bd9Sstevel@tonic-gate 	 * use of logdmux_finish_unlink() here.
9917c478bd9Sstevel@tonic-gate 	 */
9927c478bd9Sstevel@tonic-gate 	mutex_enter(&logdmux_qexch_lock);
9937c478bd9Sstevel@tonic-gate 	unlinkinfop = tmxp->unlinkinfop;
9947c478bd9Sstevel@tonic-gate 	if (unlinkinfop == NULL) {
9957c478bd9Sstevel@tonic-gate 		ASSERT(tmxp->peerq == NULL);
9967c478bd9Sstevel@tonic-gate 		tmxp->muxq = NULL;
9977c478bd9Sstevel@tonic-gate 		mutex_exit(&logdmux_qexch_lock);
9987c478bd9Sstevel@tonic-gate 		miocack(q, mp, 0, 0);
9997c478bd9Sstevel@tonic-gate 		return;
10007c478bd9Sstevel@tonic-gate 	}
10017c478bd9Sstevel@tonic-gate 	mutex_exit(&logdmux_qexch_lock);
10027c478bd9Sstevel@tonic-gate 
10037c478bd9Sstevel@tonic-gate 	mutex_enter(&unlinkinfop->state_lock);
10047c478bd9Sstevel@tonic-gate 
10057c478bd9Sstevel@tonic-gate 	switch (unlinkinfop->state) {
10067c478bd9Sstevel@tonic-gate 
10077c478bd9Sstevel@tonic-gate 	case LOGDMUX_LINKED:
10087c478bd9Sstevel@tonic-gate 		/*
10097c478bd9Sstevel@tonic-gate 		 * We're the first instance to process an I_UNLINK --
10107c478bd9Sstevel@tonic-gate 		 * ie, the peer instance is still there. We'll change
10117c478bd9Sstevel@tonic-gate 		 * the state so that only one instance is executing an
10127c478bd9Sstevel@tonic-gate 		 * I_UNLINK at any one time.
10137c478bd9Sstevel@tonic-gate 		 */
10147c478bd9Sstevel@tonic-gate 		unlinkinfop->state = LOGDMUX_UNLINK_PENDING;
10157c478bd9Sstevel@tonic-gate 		mutex_exit(&unlinkinfop->state_lock);
10167c478bd9Sstevel@tonic-gate 		/*
10177c478bd9Sstevel@tonic-gate 		 * Attach the original M_IOCTL message to a
10187c478bd9Sstevel@tonic-gate 		 * LOGDMUX_UNLINK_REQ message and send it to our peer to
10197c478bd9Sstevel@tonic-gate 		 * tell it to unlink from us. When it has completed the
10207c478bd9Sstevel@tonic-gate 		 * task, it will send us a LOGDMUX_UNLINK_RESP message
10217c478bd9Sstevel@tonic-gate 		 * with the original M_IOCTL still attached, which will be
10227c478bd9Sstevel@tonic-gate 		 * processed in our logdmuxlrput(). At that point, we will
10237c478bd9Sstevel@tonic-gate 		 * call logdmux_finish_unlink() to complete the unlink
10247c478bd9Sstevel@tonic-gate 		 * operation using the attached M_IOCTL.
10257c478bd9Sstevel@tonic-gate 		 */
10267c478bd9Sstevel@tonic-gate 		unlinkinfop->prot_mp->b_cont = mp;
10277c478bd9Sstevel@tonic-gate 		/*
10287c478bd9Sstevel@tonic-gate 		 * Put the M_CTL directly to the peer's lower RQ.
10297c478bd9Sstevel@tonic-gate 		 */
10307c478bd9Sstevel@tonic-gate 		put(RD(tmxp->peerq), unlinkinfop->prot_mp);
10317c478bd9Sstevel@tonic-gate 		break;
10327c478bd9Sstevel@tonic-gate 
10337c478bd9Sstevel@tonic-gate 	case LOGDMUX_UNLINK_PENDING:
10347c478bd9Sstevel@tonic-gate 		mutex_exit(&unlinkinfop->state_lock);
10357c478bd9Sstevel@tonic-gate 		/*
10367c478bd9Sstevel@tonic-gate 		 * Our peer is actively processing an I_UNLINK itself.
10377c478bd9Sstevel@tonic-gate 		 * We have to wait for the peer to complete and we use
10387c478bd9Sstevel@tonic-gate 		 * qtimeout as a way to poll for its completion.
10397c478bd9Sstevel@tonic-gate 		 * We save a reference to our mblk so that we can send
10407c478bd9Sstevel@tonic-gate 		 * it upstream once our peer is done.
10417c478bd9Sstevel@tonic-gate 		 */
10427c478bd9Sstevel@tonic-gate 		tmxp->unlink_mp = mp;
10437c478bd9Sstevel@tonic-gate 		tmxp->utimoutid = qtimeout(q, logdmux_unlink_timer, q,
10447c478bd9Sstevel@tonic-gate 		    drv_usectohz(LOGDMUX_POLL_WAIT));
10457c478bd9Sstevel@tonic-gate 		break;
10467c478bd9Sstevel@tonic-gate 
10477c478bd9Sstevel@tonic-gate 	case LOGDMUX_UNLINKED:
10487c478bd9Sstevel@tonic-gate 		/*
10497c478bd9Sstevel@tonic-gate 		 * Our peer is no longer linked so we can proceed.
10507c478bd9Sstevel@tonic-gate 		 */
10517c478bd9Sstevel@tonic-gate 		mutex_exit(&unlinkinfop->state_lock);
10527c478bd9Sstevel@tonic-gate 		mutex_destroy(&unlinkinfop->state_lock);
10537c478bd9Sstevel@tonic-gate 		freeb(unlinkinfop->prot_mp);
10547c478bd9Sstevel@tonic-gate 		kmem_free(unlinkinfop, sizeof (unlinkinfo_t));
10557c478bd9Sstevel@tonic-gate 		logdmux_finish_unlink(q, mp);
10567c478bd9Sstevel@tonic-gate 		break;
10577c478bd9Sstevel@tonic-gate 
10587c478bd9Sstevel@tonic-gate 	default:
10597c478bd9Sstevel@tonic-gate 		mutex_exit(&unlinkinfop->state_lock);
10607c478bd9Sstevel@tonic-gate 		cmn_err(CE_PANIC,
10617c478bd9Sstevel@tonic-gate 		    "logdmuxunlink: peer linkage is in an unrecognized state");
10627c478bd9Sstevel@tonic-gate 		break;
10637c478bd9Sstevel@tonic-gate 	}
10647c478bd9Sstevel@tonic-gate }
10657c478bd9Sstevel@tonic-gate 
10667c478bd9Sstevel@tonic-gate /*
10677c478bd9Sstevel@tonic-gate  * Finish the unlink operation.  Note that no locks should be held since
10687c478bd9Sstevel@tonic-gate  * this routine calls into other queues.
10697c478bd9Sstevel@tonic-gate  */
10707c478bd9Sstevel@tonic-gate static void
logdmux_finish_unlink(queue_t * q,mblk_t * unlink_mp)10717c478bd9Sstevel@tonic-gate logdmux_finish_unlink(queue_t *q, mblk_t *unlink_mp)
10727c478bd9Sstevel@tonic-gate {
10737c478bd9Sstevel@tonic-gate 	struct tmx *tmxp = q->q_ptr;
10747c478bd9Sstevel@tonic-gate 	mblk_t *mp;
10757c478bd9Sstevel@tonic-gate 
10767c478bd9Sstevel@tonic-gate 	/*
10777c478bd9Sstevel@tonic-gate 	 * Flush any write side data downstream.
10787c478bd9Sstevel@tonic-gate 	 */
10797c478bd9Sstevel@tonic-gate 	while ((mp = getq(WR(q))) != NULL)
10807c478bd9Sstevel@tonic-gate 		putnext(tmxp->muxq, mp);
10817c478bd9Sstevel@tonic-gate 
10827c478bd9Sstevel@tonic-gate 	/*
10837c478bd9Sstevel@tonic-gate 	 * Note that we do not NULL out q_ptr since another thread (e.g., a
10847c478bd9Sstevel@tonic-gate 	 * STREAMS service thread) might call logdmuxlrput() between the time
10857c478bd9Sstevel@tonic-gate 	 * we exit the logindmux perimeter and the time the STREAMS framework
10867c478bd9Sstevel@tonic-gate 	 * resets q_ptr to stdata (since muxq is set to NULL, any messages
10877c478bd9Sstevel@tonic-gate 	 * will just be discarded).
10887c478bd9Sstevel@tonic-gate 	 */
10897c478bd9Sstevel@tonic-gate 	tmxp->muxq = NULL;
10907c478bd9Sstevel@tonic-gate 	tmxp->unlinkinfop = NULL;
10917c478bd9Sstevel@tonic-gate 	tmxp->peerq = NULL;
10927c478bd9Sstevel@tonic-gate 	miocack(q, unlink_mp, 0, 0);
10937c478bd9Sstevel@tonic-gate }
10947c478bd9Sstevel@tonic-gate 
10957c478bd9Sstevel@tonic-gate /*
10967c478bd9Sstevel@tonic-gate  * logdmux_unlink_timer() is executed by qtimeout(). This function will
10977c478bd9Sstevel@tonic-gate  * check unlinkinfop->state to determine whether the peer has completed
10987c478bd9Sstevel@tonic-gate  * its I_UNLINK. If it hasn't, we use qtimeout() to initiate another poll.
10997c478bd9Sstevel@tonic-gate  */
11007c478bd9Sstevel@tonic-gate static void
logdmux_unlink_timer(void * arg)11017c478bd9Sstevel@tonic-gate logdmux_unlink_timer(void *arg)
11027c478bd9Sstevel@tonic-gate {
11037c478bd9Sstevel@tonic-gate 	queue_t		*q = arg;
11047c478bd9Sstevel@tonic-gate 	struct	tmx	*tmxp = q->q_ptr;
11057c478bd9Sstevel@tonic-gate 	unlinkinfo_t	*unlinkinfop = tmxp->unlinkinfop;
11067c478bd9Sstevel@tonic-gate 
11077c478bd9Sstevel@tonic-gate 	tmxp->utimoutid = 0;
11087c478bd9Sstevel@tonic-gate 
11097c478bd9Sstevel@tonic-gate 	mutex_enter(&unlinkinfop->state_lock);
11107c478bd9Sstevel@tonic-gate 
11117c478bd9Sstevel@tonic-gate 	if (unlinkinfop->state != LOGDMUX_UNLINKED) {
11127c478bd9Sstevel@tonic-gate 		ASSERT(unlinkinfop->state == LOGDMUX_UNLINK_PENDING);
11137c478bd9Sstevel@tonic-gate 		mutex_exit(&unlinkinfop->state_lock);
11147c478bd9Sstevel@tonic-gate 		/*
11157c478bd9Sstevel@tonic-gate 		 * We need to wait longer for our peer to complete.
11167c478bd9Sstevel@tonic-gate 		 */
11177c478bd9Sstevel@tonic-gate 		tmxp->utimoutid = qtimeout(q, logdmux_unlink_timer, q,
11187c478bd9Sstevel@tonic-gate 		    drv_usectohz(LOGDMUX_POLL_WAIT));
11197c478bd9Sstevel@tonic-gate 	} else {
11207c478bd9Sstevel@tonic-gate 		/*
11217c478bd9Sstevel@tonic-gate 		 * Our peer is no longer linked so we can proceed with
11227c478bd9Sstevel@tonic-gate 		 * the cleanup.
11237c478bd9Sstevel@tonic-gate 		 */
11247c478bd9Sstevel@tonic-gate 		mutex_exit(&unlinkinfop->state_lock);
11257c478bd9Sstevel@tonic-gate 		mutex_destroy(&unlinkinfop->state_lock);
11267c478bd9Sstevel@tonic-gate 		freeb(unlinkinfop->prot_mp);
11277c478bd9Sstevel@tonic-gate 		kmem_free(unlinkinfop, sizeof (unlinkinfo_t));
11287c478bd9Sstevel@tonic-gate 		logdmux_finish_unlink(q, tmxp->unlink_mp);
11297c478bd9Sstevel@tonic-gate 	}
11307c478bd9Sstevel@tonic-gate }
11317c478bd9Sstevel@tonic-gate 
11327c478bd9Sstevel@tonic-gate static void
logdmux_timer(void * arg)11337c478bd9Sstevel@tonic-gate logdmux_timer(void *arg)
11347c478bd9Sstevel@tonic-gate {
11357c478bd9Sstevel@tonic-gate 	queue_t		*q = arg;
11367c478bd9Sstevel@tonic-gate 	struct tmx	*tmxp = q->q_ptr;
11377c478bd9Sstevel@tonic-gate 
11387c478bd9Sstevel@tonic-gate 	ASSERT(tmxp != NULL);
11397c478bd9Sstevel@tonic-gate 
11407c478bd9Sstevel@tonic-gate 	if (q->q_flag & QREADR) {
11417c478bd9Sstevel@tonic-gate 		ASSERT(tmxp->rtimoutid != 0);
11427c478bd9Sstevel@tonic-gate 		tmxp->rtimoutid = 0;
11437c478bd9Sstevel@tonic-gate 	} else {
11447c478bd9Sstevel@tonic-gate 		ASSERT(tmxp->wtimoutid != 0);
11457c478bd9Sstevel@tonic-gate 		tmxp->wtimoutid = 0;
11467c478bd9Sstevel@tonic-gate 	}
11477c478bd9Sstevel@tonic-gate 	enableok(q);
11487c478bd9Sstevel@tonic-gate 	qenable(q);
11497c478bd9Sstevel@tonic-gate }
11507c478bd9Sstevel@tonic-gate 
11517c478bd9Sstevel@tonic-gate static void
logdmux_buffer(void * arg)11527c478bd9Sstevel@tonic-gate logdmux_buffer(void *arg)
11537c478bd9Sstevel@tonic-gate {
11547c478bd9Sstevel@tonic-gate 	queue_t		*q = arg;
11557c478bd9Sstevel@tonic-gate 	struct tmx	*tmxp = q->q_ptr;
11567c478bd9Sstevel@tonic-gate 
11577c478bd9Sstevel@tonic-gate 	ASSERT(tmxp != NULL);
11587c478bd9Sstevel@tonic-gate 
11597c478bd9Sstevel@tonic-gate 	if (q->q_flag & QREADR) {
11607c478bd9Sstevel@tonic-gate 		ASSERT(tmxp->rbufcid != 0);
11617c478bd9Sstevel@tonic-gate 		tmxp->rbufcid = 0;
11627c478bd9Sstevel@tonic-gate 	} else {
11637c478bd9Sstevel@tonic-gate 		ASSERT(tmxp->wbufcid != 0);
11647c478bd9Sstevel@tonic-gate 		tmxp->wbufcid = 0;
11657c478bd9Sstevel@tonic-gate 	}
11667c478bd9Sstevel@tonic-gate 	enableok(q);
11677c478bd9Sstevel@tonic-gate 	qenable(q);
11687c478bd9Sstevel@tonic-gate }
11697c478bd9Sstevel@tonic-gate 
11707c478bd9Sstevel@tonic-gate static void
recover(queue_t * q,mblk_t * mp,size_t size)11717c478bd9Sstevel@tonic-gate recover(queue_t *q, mblk_t *mp, size_t size)
11727c478bd9Sstevel@tonic-gate {
11737c478bd9Sstevel@tonic-gate 	timeout_id_t	tid;
11747c478bd9Sstevel@tonic-gate 	bufcall_id_t	bid;
11757c478bd9Sstevel@tonic-gate 	struct	tmx	*tmxp = q->q_ptr;
11767c478bd9Sstevel@tonic-gate 
11777c478bd9Sstevel@tonic-gate 	/*
11787c478bd9Sstevel@tonic-gate 	 * Avoid re-enabling the queue.
11797c478bd9Sstevel@tonic-gate 	 */
11807c478bd9Sstevel@tonic-gate 	ASSERT(queclass(mp) < QPCTL);
11817c478bd9Sstevel@tonic-gate 	ASSERT(WR(q)->q_next == NULL); /* Called from upper queue only */
11827c478bd9Sstevel@tonic-gate 	noenable(q);
11837c478bd9Sstevel@tonic-gate 	(void) putbq(q, mp);
11847c478bd9Sstevel@tonic-gate 
11857c478bd9Sstevel@tonic-gate 	/*
11867c478bd9Sstevel@tonic-gate 	 * Make sure there is at most one outstanding request per queue.
11877c478bd9Sstevel@tonic-gate 	 */
11887c478bd9Sstevel@tonic-gate 	if (q->q_flag & QREADR) {
11897c478bd9Sstevel@tonic-gate 		if (tmxp->rtimoutid != 0 || tmxp->rbufcid != 0)
11907c478bd9Sstevel@tonic-gate 			return;
11917c478bd9Sstevel@tonic-gate 	} else {
11927c478bd9Sstevel@tonic-gate 		if (tmxp->wtimoutid != 0 || tmxp->wbufcid != 0)
11937c478bd9Sstevel@tonic-gate 			return;
11947c478bd9Sstevel@tonic-gate 	}
11957c478bd9Sstevel@tonic-gate 	if (!(bid = qbufcall(RD(q), size, BPRI_MED, logdmux_buffer, q))) {
11967c478bd9Sstevel@tonic-gate 		tid = qtimeout(RD(q), logdmux_timer, q, drv_usectohz(SIMWAIT));
11977c478bd9Sstevel@tonic-gate 		if (q->q_flag & QREADR)
11987c478bd9Sstevel@tonic-gate 			tmxp->rtimoutid = tid;
11997c478bd9Sstevel@tonic-gate 		else
12007c478bd9Sstevel@tonic-gate 			tmxp->wtimoutid = tid;
12017c478bd9Sstevel@tonic-gate 	} else	{
12027c478bd9Sstevel@tonic-gate 		if (q->q_flag & QREADR)
12037c478bd9Sstevel@tonic-gate 			tmxp->rbufcid = bid;
12047c478bd9Sstevel@tonic-gate 		else
12057c478bd9Sstevel@tonic-gate 			tmxp->wbufcid = bid;
12067c478bd9Sstevel@tonic-gate 	}
12077c478bd9Sstevel@tonic-gate }
12087c478bd9Sstevel@tonic-gate 
12097c478bd9Sstevel@tonic-gate static void
flushq_dataonly(queue_t * q)12107c478bd9Sstevel@tonic-gate flushq_dataonly(queue_t *q)
12117c478bd9Sstevel@tonic-gate {
12127c478bd9Sstevel@tonic-gate 	mblk_t *mp, *nmp;
12137c478bd9Sstevel@tonic-gate 
12147c478bd9Sstevel@tonic-gate 	/*
12157c478bd9Sstevel@tonic-gate 	 * Since we are already in the perimeter, and we are not a put-shared
12167c478bd9Sstevel@tonic-gate 	 * perimeter, we don't need to freeze the stream or anything to
12177c478bd9Sstevel@tonic-gate 	 * be ensured of exclusivity.
12187c478bd9Sstevel@tonic-gate 	 */
12197c478bd9Sstevel@tonic-gate 	mp = q->q_first;
12207c478bd9Sstevel@tonic-gate 	while (mp != NULL) {
12217c478bd9Sstevel@tonic-gate 		if (mp->b_datap->db_type == M_DATA) {
12227c478bd9Sstevel@tonic-gate 			nmp = mp->b_next;
12237c478bd9Sstevel@tonic-gate 			rmvq(q, mp);
12247c478bd9Sstevel@tonic-gate 			freemsg(mp);
12257c478bd9Sstevel@tonic-gate 			mp = nmp;
12267c478bd9Sstevel@tonic-gate 		} else {
12277c478bd9Sstevel@tonic-gate 			mp = mp->b_next;
12287c478bd9Sstevel@tonic-gate 		}
12297c478bd9Sstevel@tonic-gate 	}
12307c478bd9Sstevel@tonic-gate }
12317c478bd9Sstevel@tonic-gate 
12327c478bd9Sstevel@tonic-gate /*
12337c478bd9Sstevel@tonic-gate  * logdmux_alloc_unlinkinfo() is called from logdmuxuwput() during the
12347c478bd9Sstevel@tonic-gate  * processing of a LOGDMX_IOC_QEXCHANGE ioctl() to allocate the
12357c478bd9Sstevel@tonic-gate  * unlinkinfo_t which is needed during the processing of an I_UNLINK.
12367c478bd9Sstevel@tonic-gate  */
12377c478bd9Sstevel@tonic-gate static int
logdmux_alloc_unlinkinfo(struct tmx * t0,struct tmx * t1)12387c478bd9Sstevel@tonic-gate logdmux_alloc_unlinkinfo(struct tmx *t0, struct tmx *t1)
12397c478bd9Sstevel@tonic-gate {
12407c478bd9Sstevel@tonic-gate 	unlinkinfo_t	*p;
12417c478bd9Sstevel@tonic-gate 	uint_t		*messagep;
12427c478bd9Sstevel@tonic-gate 
12437c478bd9Sstevel@tonic-gate 	if ((p = kmem_zalloc(sizeof (unlinkinfo_t), KM_NOSLEEP)) == NULL)
12447c478bd9Sstevel@tonic-gate 		return (ENOSR);
12457c478bd9Sstevel@tonic-gate 
12467c478bd9Sstevel@tonic-gate 	if ((p->prot_mp = allocb(sizeof (uint_t), BPRI_MED)) == NULL) {
12477c478bd9Sstevel@tonic-gate 		kmem_free(p, sizeof (unlinkinfo_t));
12487c478bd9Sstevel@tonic-gate 		return (ENOSR);
12497c478bd9Sstevel@tonic-gate 	}
12507c478bd9Sstevel@tonic-gate 
12517c478bd9Sstevel@tonic-gate 	DB_TYPE(p->prot_mp) = M_CTL;
12527c478bd9Sstevel@tonic-gate 	messagep = (uint_t *)p->prot_mp->b_wptr;
12537c478bd9Sstevel@tonic-gate 	*messagep = LOGDMUX_UNLINK_REQ;
12547c478bd9Sstevel@tonic-gate 	p->prot_mp->b_wptr += sizeof (*messagep);
12557c478bd9Sstevel@tonic-gate 	p->state = LOGDMUX_LINKED;
12567c478bd9Sstevel@tonic-gate 	mutex_init(&p->state_lock, NULL, MUTEX_DRIVER, NULL);
12577c478bd9Sstevel@tonic-gate 
12587c478bd9Sstevel@tonic-gate 	t0->unlinkinfop = t1->unlinkinfop = p;
12597c478bd9Sstevel@tonic-gate 
12607c478bd9Sstevel@tonic-gate 	return (0);
12617c478bd9Sstevel@tonic-gate }
1262