10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*7656SSherry.Moore@Sun.COM * Common Development and Distribution License (the "License").
6*7656SSherry.Moore@Sun.COM * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
22*7656SSherry.Moore@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate
270Sstevel@tonic-gate /*
280Sstevel@tonic-gate * Description: logindmux.c
290Sstevel@tonic-gate *
300Sstevel@tonic-gate * The logindmux driver is used with login modules (like telmod/rlmod).
310Sstevel@tonic-gate * This is a 1x1 cloning mux and two of these muxes are used. The lower link
320Sstevel@tonic-gate * of one of the muxes receives input from net and the lower link of the
330Sstevel@tonic-gate * other mux receives input from pseudo terminal subsystem.
340Sstevel@tonic-gate *
350Sstevel@tonic-gate * The logdmux_qexch_lock mutex manages the race between LOGDMX_IOC_QEXCHANGE,
360Sstevel@tonic-gate * logdmuxunlink() and logdmuxclose(), so that the instance selected as a peer
370Sstevel@tonic-gate * in LOGDMX_IOC_QEXCHANGE cannot be unlinked or closed until the qexchange
380Sstevel@tonic-gate * is complete; see the inline comments in the code for details.
390Sstevel@tonic-gate *
400Sstevel@tonic-gate * The logdmux_peerq_lock mutex manages the race between logdmuxlwsrv() and
410Sstevel@tonic-gate * logdmuxlrput() (when null'ing tmxp->peerq during LOGDMUX_UNLINK_REQ
420Sstevel@tonic-gate * processing).
430Sstevel@tonic-gate *
440Sstevel@tonic-gate * The logdmux_minor_lock mutex serializes the growth of logdmux_minor_arena
450Sstevel@tonic-gate * (the arena is grown gradually rather than allocated all at once so that
460Sstevel@tonic-gate * minor numbers are recycled sooner; for simplicity it is never shrunk).
470Sstevel@tonic-gate *
480Sstevel@tonic-gate * The unlink operation is implemented using protocol messages that flow
490Sstevel@tonic-gate * between the two logindmux peer instances. The instance processing the
500Sstevel@tonic-gate * I_UNLINK ioctl will send a LOGDMUX_UNLINK_REQ protocol message to its
510Sstevel@tonic-gate * peer to indicate that it wishes to unlink; the peer will process this
520Sstevel@tonic-gate * message in its lrput, null its tmxp->peerq and then send a
530Sstevel@tonic-gate * LOGDMUX_UNLINK_RESP protocol message in reply to indicate that the
540Sstevel@tonic-gate * unlink can proceed; having received the reply in its lrput, the
550Sstevel@tonic-gate * instance processing the I_UNLINK can then continue. To ensure that only
560Sstevel@tonic-gate * one of the peer instances will be actively processing an I_UNLINK at
570Sstevel@tonic-gate * any one time, a single structure (an unlinkinfo_t containing a mutex,
580Sstevel@tonic-gate * state variable and pointer to an M_CTL mblk) is allocated during
590Sstevel@tonic-gate * the processing of the LOGDMX_IOC_QEXCHANGE ioctl. The two instances, if
600Sstevel@tonic-gate * trying to unlink simultaneously, will race to get control of this
610Sstevel@tonic-gate * structure which contains the resources necessary to process the
620Sstevel@tonic-gate * I_UNLINK. The instance that wins this race will be able to continue
630Sstevel@tonic-gate * with the unlink whilst the other instance will be obliged to wait.
640Sstevel@tonic-gate */
650Sstevel@tonic-gate
660Sstevel@tonic-gate #include <sys/types.h>
670Sstevel@tonic-gate #include <sys/param.h>
680Sstevel@tonic-gate #include <sys/errno.h>
690Sstevel@tonic-gate #include <sys/debug.h>
700Sstevel@tonic-gate #include <sys/stropts.h>
710Sstevel@tonic-gate #include <sys/stream.h>
720Sstevel@tonic-gate #include <sys/logindmux.h>
730Sstevel@tonic-gate #include <sys/logindmux_impl.h>
740Sstevel@tonic-gate #include <sys/stat.h>
750Sstevel@tonic-gate #include <sys/kmem.h>
760Sstevel@tonic-gate #include <sys/vmem.h>
770Sstevel@tonic-gate #include <sys/strsun.h>
780Sstevel@tonic-gate #include <sys/sysmacros.h>
790Sstevel@tonic-gate #include <sys/mkdev.h>
800Sstevel@tonic-gate #include <sys/ddi.h>
810Sstevel@tonic-gate #include <sys/sunddi.h>
820Sstevel@tonic-gate #include <sys/modctl.h>
830Sstevel@tonic-gate #include <sys/termios.h>
840Sstevel@tonic-gate #include <sys/cmn_err.h>
850Sstevel@tonic-gate
860Sstevel@tonic-gate static int logdmuxopen(queue_t *, dev_t *, int, int, cred_t *);
870Sstevel@tonic-gate static int logdmuxclose(queue_t *, int, cred_t *);
880Sstevel@tonic-gate static int logdmuxursrv(queue_t *);
890Sstevel@tonic-gate static int logdmuxuwput(queue_t *, mblk_t *);
900Sstevel@tonic-gate static int logdmuxlrput(queue_t *, mblk_t *);
910Sstevel@tonic-gate static int logdmuxlrsrv(queue_t *);
920Sstevel@tonic-gate static int logdmuxlwsrv(queue_t *);
930Sstevel@tonic-gate static int logdmuxuwsrv(queue_t *);
940Sstevel@tonic-gate static int logdmux_alloc_unlinkinfo(struct tmx *, struct tmx *);
950Sstevel@tonic-gate
960Sstevel@tonic-gate static void logdmuxlink(queue_t *, mblk_t *);
970Sstevel@tonic-gate static void logdmuxunlink(queue_t *, mblk_t *);
980Sstevel@tonic-gate static void logdmux_finish_unlink(queue_t *, mblk_t *);
990Sstevel@tonic-gate static void logdmux_unlink_timer(void *arg);
1000Sstevel@tonic-gate static void recover(queue_t *, mblk_t *, size_t);
1010Sstevel@tonic-gate static void flushq_dataonly(queue_t *);
1020Sstevel@tonic-gate
1030Sstevel@tonic-gate static kmutex_t logdmux_qexch_lock;
1040Sstevel@tonic-gate static kmutex_t logdmux_peerq_lock;
1050Sstevel@tonic-gate static kmutex_t logdmux_minor_lock;
1060Sstevel@tonic-gate static minor_t logdmux_maxminor = 256; /* grown as necessary */
1070Sstevel@tonic-gate static vmem_t *logdmux_minor_arena;
1080Sstevel@tonic-gate static void *logdmux_statep;
1090Sstevel@tonic-gate
1100Sstevel@tonic-gate static struct module_info logdmuxm_info = {
1110Sstevel@tonic-gate LOGDMX_ID,
1120Sstevel@tonic-gate "logindmux",
1130Sstevel@tonic-gate 0,
1140Sstevel@tonic-gate 256,
1150Sstevel@tonic-gate 512,
1160Sstevel@tonic-gate 256
1170Sstevel@tonic-gate };
1180Sstevel@tonic-gate
1190Sstevel@tonic-gate static struct qinit logdmuxurinit = {
1200Sstevel@tonic-gate NULL,
1210Sstevel@tonic-gate logdmuxursrv,
1220Sstevel@tonic-gate logdmuxopen,
1230Sstevel@tonic-gate logdmuxclose,
1240Sstevel@tonic-gate NULL,
1250Sstevel@tonic-gate &logdmuxm_info
1260Sstevel@tonic-gate };
1270Sstevel@tonic-gate
1280Sstevel@tonic-gate static struct qinit logdmuxuwinit = {
1290Sstevel@tonic-gate logdmuxuwput,
1300Sstevel@tonic-gate logdmuxuwsrv,
1310Sstevel@tonic-gate NULL,
1320Sstevel@tonic-gate NULL,
1330Sstevel@tonic-gate NULL,
1340Sstevel@tonic-gate &logdmuxm_info
1350Sstevel@tonic-gate };
1360Sstevel@tonic-gate
1370Sstevel@tonic-gate static struct qinit logdmuxlrinit = {
1380Sstevel@tonic-gate logdmuxlrput,
1390Sstevel@tonic-gate logdmuxlrsrv,
1400Sstevel@tonic-gate NULL,
1410Sstevel@tonic-gate NULL,
1420Sstevel@tonic-gate NULL,
1430Sstevel@tonic-gate &logdmuxm_info
1440Sstevel@tonic-gate };
1450Sstevel@tonic-gate
1460Sstevel@tonic-gate static struct qinit logdmuxlwinit = {
1470Sstevel@tonic-gate NULL,
1480Sstevel@tonic-gate logdmuxlwsrv,
1490Sstevel@tonic-gate NULL,
1500Sstevel@tonic-gate NULL,
1510Sstevel@tonic-gate NULL,
1520Sstevel@tonic-gate &logdmuxm_info
1530Sstevel@tonic-gate };
1540Sstevel@tonic-gate
1550Sstevel@tonic-gate struct streamtab logdmuxinfo = {
1560Sstevel@tonic-gate &logdmuxurinit,
1570Sstevel@tonic-gate &logdmuxuwinit,
1580Sstevel@tonic-gate &logdmuxlrinit,
1590Sstevel@tonic-gate &logdmuxlwinit
1600Sstevel@tonic-gate };
1610Sstevel@tonic-gate
1620Sstevel@tonic-gate static int logdmux_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
1630Sstevel@tonic-gate static int logdmux_attach(dev_info_t *, ddi_attach_cmd_t);
1640Sstevel@tonic-gate static int logdmux_detach(dev_info_t *, ddi_detach_cmd_t);
1650Sstevel@tonic-gate static dev_info_t *logdmux_dip;
1660Sstevel@tonic-gate
1670Sstevel@tonic-gate DDI_DEFINE_STREAM_OPS(logdmux_ops, nulldev, nulldev, logdmux_attach,
168*7656SSherry.Moore@Sun.COM logdmux_detach, nulldev, logdmux_info, D_MP | D_MTPERQ, &logdmuxinfo,
169*7656SSherry.Moore@Sun.COM ddi_quiesce_not_needed);
1700Sstevel@tonic-gate
1710Sstevel@tonic-gate static struct modldrv modldrv = {
1720Sstevel@tonic-gate &mod_driverops,
173*7656SSherry.Moore@Sun.COM "logindmux driver",
1740Sstevel@tonic-gate &logdmux_ops
1750Sstevel@tonic-gate };
1760Sstevel@tonic-gate
1770Sstevel@tonic-gate static struct modlinkage modlinkage = {
1780Sstevel@tonic-gate MODREV_1, &modldrv, NULL
1790Sstevel@tonic-gate };
1800Sstevel@tonic-gate
1810Sstevel@tonic-gate int
_init(void)1820Sstevel@tonic-gate _init(void)
1830Sstevel@tonic-gate {
1840Sstevel@tonic-gate int ret;
1850Sstevel@tonic-gate
1860Sstevel@tonic-gate mutex_init(&logdmux_peerq_lock, NULL, MUTEX_DRIVER, NULL);
1870Sstevel@tonic-gate mutex_init(&logdmux_qexch_lock, NULL, MUTEX_DRIVER, NULL);
1880Sstevel@tonic-gate
1890Sstevel@tonic-gate if ((ret = mod_install(&modlinkage)) != 0) {
1900Sstevel@tonic-gate mutex_destroy(&logdmux_peerq_lock);
1910Sstevel@tonic-gate mutex_destroy(&logdmux_qexch_lock);
1920Sstevel@tonic-gate return (ret);
1930Sstevel@tonic-gate }
1940Sstevel@tonic-gate
1950Sstevel@tonic-gate logdmux_minor_arena = vmem_create("logdmux_minor", (void *)1,
1960Sstevel@tonic-gate logdmux_maxminor, 1, NULL, NULL, NULL, 0,
1970Sstevel@tonic-gate VM_SLEEP | VMC_IDENTIFIER);
1980Sstevel@tonic-gate (void) ddi_soft_state_init(&logdmux_statep, sizeof (struct tmx), 1);
1990Sstevel@tonic-gate
2000Sstevel@tonic-gate return (0);
2010Sstevel@tonic-gate }
2020Sstevel@tonic-gate
2030Sstevel@tonic-gate int
_fini(void)2040Sstevel@tonic-gate _fini(void)
2050Sstevel@tonic-gate {
2060Sstevel@tonic-gate int ret;
2070Sstevel@tonic-gate
2080Sstevel@tonic-gate if ((ret = mod_remove(&modlinkage)) == 0) {
2090Sstevel@tonic-gate mutex_destroy(&logdmux_peerq_lock);
2100Sstevel@tonic-gate mutex_destroy(&logdmux_qexch_lock);
2110Sstevel@tonic-gate ddi_soft_state_fini(&logdmux_statep);
2120Sstevel@tonic-gate vmem_destroy(logdmux_minor_arena);
2130Sstevel@tonic-gate logdmux_minor_arena = NULL;
2140Sstevel@tonic-gate }
2150Sstevel@tonic-gate
2160Sstevel@tonic-gate return (ret);
2170Sstevel@tonic-gate }
2180Sstevel@tonic-gate
2190Sstevel@tonic-gate int
_info(struct modinfo * modinfop)2200Sstevel@tonic-gate _info(struct modinfo *modinfop)
2210Sstevel@tonic-gate {
2220Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop));
2230Sstevel@tonic-gate }
2240Sstevel@tonic-gate
2250Sstevel@tonic-gate static int
logdmux_attach(dev_info_t * devi,ddi_attach_cmd_t cmd)2260Sstevel@tonic-gate logdmux_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
2270Sstevel@tonic-gate {
2280Sstevel@tonic-gate if (cmd != DDI_ATTACH)
2290Sstevel@tonic-gate return (DDI_FAILURE);
2300Sstevel@tonic-gate
2310Sstevel@tonic-gate if (ddi_create_minor_node(devi, "logindmux", S_IFCHR, 0, DDI_PSEUDO,
2320Sstevel@tonic-gate CLONE_DEV) == DDI_FAILURE)
2330Sstevel@tonic-gate return (DDI_FAILURE);
2340Sstevel@tonic-gate
2350Sstevel@tonic-gate logdmux_dip = devi;
2360Sstevel@tonic-gate return (DDI_SUCCESS);
2370Sstevel@tonic-gate }
2380Sstevel@tonic-gate
2390Sstevel@tonic-gate static int
logdmux_detach(dev_info_t * devi,ddi_detach_cmd_t cmd)2400Sstevel@tonic-gate logdmux_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
2410Sstevel@tonic-gate {
2420Sstevel@tonic-gate if (cmd != DDI_DETACH)
2430Sstevel@tonic-gate return (DDI_FAILURE);
2440Sstevel@tonic-gate
2450Sstevel@tonic-gate ddi_remove_minor_node(devi, NULL);
2460Sstevel@tonic-gate return (DDI_SUCCESS);
2470Sstevel@tonic-gate }
2480Sstevel@tonic-gate
2490Sstevel@tonic-gate /* ARGSUSED */
2500Sstevel@tonic-gate static int
logdmux_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)2510Sstevel@tonic-gate logdmux_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
2520Sstevel@tonic-gate {
2530Sstevel@tonic-gate int error;
2540Sstevel@tonic-gate
2550Sstevel@tonic-gate switch (infocmd) {
2560Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO:
2570Sstevel@tonic-gate if (logdmux_dip == NULL) {
2580Sstevel@tonic-gate error = DDI_FAILURE;
2590Sstevel@tonic-gate } else {
2600Sstevel@tonic-gate *result = logdmux_dip;
2610Sstevel@tonic-gate error = DDI_SUCCESS;
2620Sstevel@tonic-gate }
2630Sstevel@tonic-gate break;
2640Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE:
2650Sstevel@tonic-gate *result = (void *)0;
2660Sstevel@tonic-gate error = DDI_SUCCESS;
2670Sstevel@tonic-gate break;
2680Sstevel@tonic-gate default:
2690Sstevel@tonic-gate error = DDI_FAILURE;
2700Sstevel@tonic-gate }
2710Sstevel@tonic-gate return (error);
2720Sstevel@tonic-gate }
2730Sstevel@tonic-gate
2740Sstevel@tonic-gate /*
2750Sstevel@tonic-gate * Logindmux open routine
2760Sstevel@tonic-gate */
2770Sstevel@tonic-gate /*ARGSUSED*/
2780Sstevel@tonic-gate static int
logdmuxopen(queue_t * q,dev_t * devp,int flag,int sflag,cred_t * crp)2790Sstevel@tonic-gate logdmuxopen(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *crp)
2800Sstevel@tonic-gate {
2810Sstevel@tonic-gate struct tmx *tmxp;
2820Sstevel@tonic-gate minor_t minor, omaxminor;
2830Sstevel@tonic-gate
2840Sstevel@tonic-gate if (sflag != CLONEOPEN)
2850Sstevel@tonic-gate return (EINVAL);
2860Sstevel@tonic-gate
2870Sstevel@tonic-gate mutex_enter(&logdmux_minor_lock);
2880Sstevel@tonic-gate if (vmem_size(logdmux_minor_arena, VMEM_FREE) == 0) {
2890Sstevel@tonic-gate /*
2900Sstevel@tonic-gate * The arena has been exhausted; grow by powers of two
2910Sstevel@tonic-gate * up to MAXMIN; bail if we've run out of minors.
2920Sstevel@tonic-gate */
2930Sstevel@tonic-gate if (logdmux_maxminor == MAXMIN) {
2940Sstevel@tonic-gate mutex_exit(&logdmux_minor_lock);
2950Sstevel@tonic-gate return (ENOMEM);
2960Sstevel@tonic-gate }
2970Sstevel@tonic-gate
2980Sstevel@tonic-gate omaxminor = logdmux_maxminor;
2990Sstevel@tonic-gate logdmux_maxminor = MIN(logdmux_maxminor << 1, MAXMIN);
3000Sstevel@tonic-gate
3010Sstevel@tonic-gate (void) vmem_add(logdmux_minor_arena,
3020Sstevel@tonic-gate (void *)(uintptr_t)(omaxminor + 1),
3030Sstevel@tonic-gate logdmux_maxminor - omaxminor, VM_SLEEP);
3040Sstevel@tonic-gate }
3050Sstevel@tonic-gate minor = (minor_t)(uintptr_t)
3060Sstevel@tonic-gate vmem_alloc(logdmux_minor_arena, 1, VM_SLEEP);
3070Sstevel@tonic-gate mutex_exit(&logdmux_minor_lock);
3080Sstevel@tonic-gate
3090Sstevel@tonic-gate if (ddi_soft_state_zalloc(logdmux_statep, minor) == DDI_FAILURE) {
3100Sstevel@tonic-gate vmem_free(logdmux_minor_arena, (void *)(uintptr_t)minor, 1);
3110Sstevel@tonic-gate return (ENOMEM);
3120Sstevel@tonic-gate }
3130Sstevel@tonic-gate
3140Sstevel@tonic-gate tmxp = ddi_get_soft_state(logdmux_statep, minor);
3150Sstevel@tonic-gate tmxp->rdq = q;
3160Sstevel@tonic-gate tmxp->muxq = NULL;
3170Sstevel@tonic-gate tmxp->peerq = NULL;
3180Sstevel@tonic-gate tmxp->unlinkinfop = NULL;
3190Sstevel@tonic-gate tmxp->dev0 = minor;
3200Sstevel@tonic-gate
3210Sstevel@tonic-gate *devp = makedevice(getmajor(*devp), tmxp->dev0);
3220Sstevel@tonic-gate q->q_ptr = tmxp;
3230Sstevel@tonic-gate WR(q)->q_ptr = tmxp;
3240Sstevel@tonic-gate
3250Sstevel@tonic-gate qprocson(q);
3260Sstevel@tonic-gate return (0);
3270Sstevel@tonic-gate }
3280Sstevel@tonic-gate
3290Sstevel@tonic-gate /*
3300Sstevel@tonic-gate * Logindmux close routine gets called when telnet connection is closed
3310Sstevel@tonic-gate */
3320Sstevel@tonic-gate /*ARGSUSED*/
3330Sstevel@tonic-gate static int
logdmuxclose(queue_t * q,int flag,cred_t * crp)3340Sstevel@tonic-gate logdmuxclose(queue_t *q, int flag, cred_t *crp)
3350Sstevel@tonic-gate {
3360Sstevel@tonic-gate struct tmx *tmxp = q->q_ptr;
3370Sstevel@tonic-gate minor_t minor = tmxp->dev0;
3380Sstevel@tonic-gate
3390Sstevel@tonic-gate ASSERT(tmxp->muxq == NULL);
3400Sstevel@tonic-gate ASSERT(tmxp->peerq == NULL);
3410Sstevel@tonic-gate
3420Sstevel@tonic-gate qprocsoff(q);
3430Sstevel@tonic-gate if (tmxp->wbufcid != 0) {
3440Sstevel@tonic-gate qunbufcall(q, tmxp->wbufcid);
3450Sstevel@tonic-gate tmxp->wbufcid = 0;
3460Sstevel@tonic-gate }
3470Sstevel@tonic-gate if (tmxp->rbufcid != 0) {
3480Sstevel@tonic-gate qunbufcall(q, tmxp->rbufcid);
3490Sstevel@tonic-gate tmxp->rbufcid = 0;
3500Sstevel@tonic-gate }
3510Sstevel@tonic-gate if (tmxp->rtimoutid != 0) {
3520Sstevel@tonic-gate (void) quntimeout(q, tmxp->rtimoutid);
3530Sstevel@tonic-gate tmxp->rtimoutid = 0;
3540Sstevel@tonic-gate }
3550Sstevel@tonic-gate if (tmxp->wtimoutid != 0) {
3560Sstevel@tonic-gate (void) quntimeout(q, tmxp->wtimoutid);
3570Sstevel@tonic-gate tmxp->wtimoutid = 0;
3580Sstevel@tonic-gate }
3590Sstevel@tonic-gate if (tmxp->utimoutid != 0) {
3600Sstevel@tonic-gate (void) quntimeout(q, tmxp->utimoutid);
3610Sstevel@tonic-gate tmxp->utimoutid = 0;
3620Sstevel@tonic-gate }
3630Sstevel@tonic-gate
3640Sstevel@tonic-gate /*
3650Sstevel@tonic-gate * Hold logdmux_qexch_lock to prevent another thread that might be
3660Sstevel@tonic-gate * in LOGDMX_IOC_QEXCHANGE from looking up our state while we're
3670Sstevel@tonic-gate * disposing of it.
3680Sstevel@tonic-gate */
3690Sstevel@tonic-gate mutex_enter(&logdmux_qexch_lock);
3700Sstevel@tonic-gate ddi_soft_state_free(logdmux_statep, minor);
3710Sstevel@tonic-gate vmem_free(logdmux_minor_arena, (void *)(uintptr_t)minor, 1);
3720Sstevel@tonic-gate mutex_exit(&logdmux_qexch_lock);
3730Sstevel@tonic-gate
3740Sstevel@tonic-gate q->q_ptr = NULL;
3750Sstevel@tonic-gate WR(q)->q_ptr = NULL;
3760Sstevel@tonic-gate
3770Sstevel@tonic-gate return (0);
3780Sstevel@tonic-gate }
3790Sstevel@tonic-gate
3800Sstevel@tonic-gate /*
3810Sstevel@tonic-gate * Upper read service routine
3820Sstevel@tonic-gate */
3830Sstevel@tonic-gate static int
logdmuxursrv(queue_t * q)3840Sstevel@tonic-gate logdmuxursrv(queue_t *q)
3850Sstevel@tonic-gate {
3860Sstevel@tonic-gate struct tmx *tmxp = q->q_ptr;
3870Sstevel@tonic-gate
3880Sstevel@tonic-gate if (tmxp->muxq != NULL)
3890Sstevel@tonic-gate qenable(RD(tmxp->muxq));
3900Sstevel@tonic-gate return (0);
3910Sstevel@tonic-gate }
3920Sstevel@tonic-gate
3930Sstevel@tonic-gate /*
3940Sstevel@tonic-gate * This routine gets called when telnet daemon sends data or ioctl messages
3950Sstevel@tonic-gate * to upper mux queue.
3960Sstevel@tonic-gate */
3970Sstevel@tonic-gate static int
logdmuxuwput(queue_t * q,mblk_t * mp)3980Sstevel@tonic-gate logdmuxuwput(queue_t *q, mblk_t *mp)
3990Sstevel@tonic-gate {
4000Sstevel@tonic-gate queue_t *qp;
4010Sstevel@tonic-gate mblk_t *newmp;
4020Sstevel@tonic-gate struct iocblk *ioc;
4030Sstevel@tonic-gate minor_t minor;
4040Sstevel@tonic-gate STRUCT_HANDLE(protocol_arg, protoh);
4050Sstevel@tonic-gate struct tmx *tmxp, *tmxpeerp;
4060Sstevel@tonic-gate int error;
4070Sstevel@tonic-gate
4080Sstevel@tonic-gate tmxp = q->q_ptr;
4090Sstevel@tonic-gate
4100Sstevel@tonic-gate switch (mp->b_datap->db_type) {
4110Sstevel@tonic-gate
4120Sstevel@tonic-gate case M_IOCTL:
4130Sstevel@tonic-gate ASSERT(MBLKL(mp) == sizeof (struct iocblk));
4140Sstevel@tonic-gate
4150Sstevel@tonic-gate ioc = (struct iocblk *)mp->b_rptr;
4160Sstevel@tonic-gate switch (ioc->ioc_cmd) {
4170Sstevel@tonic-gate /*
4180Sstevel@tonic-gate * This is a special ioctl which exchanges q info
4190Sstevel@tonic-gate * of the two peers, connected to netf and ptmx.
4200Sstevel@tonic-gate */
4210Sstevel@tonic-gate case LOGDMX_IOC_QEXCHANGE:
4220Sstevel@tonic-gate error = miocpullup(mp,
4230Sstevel@tonic-gate SIZEOF_STRUCT(protocol_arg, ioc->ioc_flag));
4240Sstevel@tonic-gate if (error != 0) {
4250Sstevel@tonic-gate miocnak(q, mp, 0, error);
4260Sstevel@tonic-gate break;
4270Sstevel@tonic-gate }
4280Sstevel@tonic-gate STRUCT_SET_HANDLE(protoh, ioc->ioc_flag,
4290Sstevel@tonic-gate (struct protocol_arg *)mp->b_cont->b_rptr);
4300Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
4310Sstevel@tonic-gate if ((ioc->ioc_flag & DATAMODEL_MASK) ==
4320Sstevel@tonic-gate DATAMODEL_ILP32) {
4330Sstevel@tonic-gate minor = getminor(expldev(
4340Sstevel@tonic-gate STRUCT_FGET(protoh, dev)));
4350Sstevel@tonic-gate } else
4360Sstevel@tonic-gate #endif
4370Sstevel@tonic-gate {
4380Sstevel@tonic-gate minor = getminor(STRUCT_FGET(protoh, dev));
4390Sstevel@tonic-gate }
4400Sstevel@tonic-gate
4410Sstevel@tonic-gate /*
4420Sstevel@tonic-gate * The second argument to ddi_get_soft_state() is
4430Sstevel@tonic-gate * interpreted as an `int', so prohibit negative
4440Sstevel@tonic-gate * values.
4450Sstevel@tonic-gate */
4460Sstevel@tonic-gate if ((int)minor < 0) {
4470Sstevel@tonic-gate miocnak(q, mp, 0, EINVAL);
4480Sstevel@tonic-gate break;
4490Sstevel@tonic-gate }
4500Sstevel@tonic-gate
4510Sstevel@tonic-gate /*
4520Sstevel@tonic-gate * We must hold logdmux_qexch_lock while looking up
4530Sstevel@tonic-gate * the proposed peer to prevent another thread from
4540Sstevel@tonic-gate * simultaneously I_UNLINKing or closing it.
4550Sstevel@tonic-gate */
4560Sstevel@tonic-gate mutex_enter(&logdmux_qexch_lock);
4570Sstevel@tonic-gate
4580Sstevel@tonic-gate /*
4590Sstevel@tonic-gate * For LOGDMX_IOC_QEXCHANGE to succeed, our peer must
4600Sstevel@tonic-gate * exist (and not be us), and both we and our peer
4610Sstevel@tonic-gate * must be I_LINKed (i.e., muxq must not be NULL) and
4620Sstevel@tonic-gate * not already have a peer.
4630Sstevel@tonic-gate */
4640Sstevel@tonic-gate tmxpeerp = ddi_get_soft_state(logdmux_statep, minor);
4650Sstevel@tonic-gate if (tmxpeerp == NULL || tmxpeerp == tmxp ||
4660Sstevel@tonic-gate tmxpeerp->muxq == NULL || tmxpeerp->peerq != NULL ||
4670Sstevel@tonic-gate tmxp->muxq == NULL || tmxp->peerq != NULL) {
4680Sstevel@tonic-gate mutex_exit(&logdmux_qexch_lock);
4690Sstevel@tonic-gate miocnak(q, mp, 0, EINVAL);
4700Sstevel@tonic-gate break;
4710Sstevel@tonic-gate }
4720Sstevel@tonic-gate
4730Sstevel@tonic-gate /*
4740Sstevel@tonic-gate * If `flag' is set then exchange queues and assume
4750Sstevel@tonic-gate * tmxp refers to the ptmx stream.
4760Sstevel@tonic-gate */
4770Sstevel@tonic-gate if (STRUCT_FGET(protoh, flag)) {
4780Sstevel@tonic-gate /*
4790Sstevel@tonic-gate * Allocate and populate the structure we
4800Sstevel@tonic-gate * need when processing an I_UNLINK ioctl.
4810Sstevel@tonic-gate * Give both logindmux instances a pointer
4820Sstevel@tonic-gate * to it from their tmx structure.
4830Sstevel@tonic-gate */
4840Sstevel@tonic-gate if ((error = logdmux_alloc_unlinkinfo(
4850Sstevel@tonic-gate tmxp, tmxpeerp)) != 0) {
4860Sstevel@tonic-gate mutex_exit(&logdmux_qexch_lock);
4870Sstevel@tonic-gate miocnak(q, mp, 0, error);
4880Sstevel@tonic-gate break;
4890Sstevel@tonic-gate }
4900Sstevel@tonic-gate tmxp->peerq = tmxpeerp->muxq;
4910Sstevel@tonic-gate tmxpeerp->peerq = tmxp->muxq;
4920Sstevel@tonic-gate tmxp->isptm = B_TRUE;
4930Sstevel@tonic-gate }
4940Sstevel@tonic-gate mutex_exit(&logdmux_qexch_lock);
4950Sstevel@tonic-gate miocack(q, mp, 0, 0);
4960Sstevel@tonic-gate break;
4970Sstevel@tonic-gate
4980Sstevel@tonic-gate case I_LINK:
4990Sstevel@tonic-gate ASSERT(MBLKL(mp->b_cont) == sizeof (struct linkblk));
5000Sstevel@tonic-gate logdmuxlink(q, mp);
5010Sstevel@tonic-gate break;
5020Sstevel@tonic-gate
5030Sstevel@tonic-gate case I_UNLINK:
5040Sstevel@tonic-gate ASSERT(MBLKL(mp->b_cont) == sizeof (struct linkblk));
5050Sstevel@tonic-gate logdmuxunlink(q, mp);
5060Sstevel@tonic-gate break;
5070Sstevel@tonic-gate
5080Sstevel@tonic-gate default:
5090Sstevel@tonic-gate if (tmxp->muxq == NULL) {
5100Sstevel@tonic-gate miocnak(q, mp, 0, EINVAL);
5110Sstevel@tonic-gate return (0);
5120Sstevel@tonic-gate }
5130Sstevel@tonic-gate putnext(tmxp->muxq, mp);
5140Sstevel@tonic-gate break;
5150Sstevel@tonic-gate }
5160Sstevel@tonic-gate
5170Sstevel@tonic-gate break;
5180Sstevel@tonic-gate
5190Sstevel@tonic-gate case M_DATA:
5200Sstevel@tonic-gate if (!tmxp->isptm) {
5210Sstevel@tonic-gate if ((newmp = allocb(sizeof (char), BPRI_MED)) == NULL) {
5220Sstevel@tonic-gate recover(q, mp, sizeof (char));
5230Sstevel@tonic-gate return (0);
5240Sstevel@tonic-gate }
5250Sstevel@tonic-gate newmp->b_datap->db_type = M_CTL;
5260Sstevel@tonic-gate *newmp->b_wptr++ = M_CTL_MAGIC_NUMBER;
5270Sstevel@tonic-gate newmp->b_cont = mp;
5280Sstevel@tonic-gate mp = newmp;
5290Sstevel@tonic-gate }
5300Sstevel@tonic-gate /* FALLTHRU */
5310Sstevel@tonic-gate
5320Sstevel@tonic-gate case M_PROTO:
5330Sstevel@tonic-gate case M_PCPROTO:
5340Sstevel@tonic-gate qp = tmxp->muxq;
5350Sstevel@tonic-gate if (qp == NULL) {
5360Sstevel@tonic-gate merror(q, mp, EINVAL);
5370Sstevel@tonic-gate return (0);
5380Sstevel@tonic-gate }
5390Sstevel@tonic-gate
5400Sstevel@tonic-gate if (queclass(mp) < QPCTL) {
5410Sstevel@tonic-gate if (q->q_first != NULL || !canputnext(qp)) {
5420Sstevel@tonic-gate (void) putq(q, mp);
5430Sstevel@tonic-gate return (0);
5440Sstevel@tonic-gate }
5450Sstevel@tonic-gate }
5460Sstevel@tonic-gate putnext(qp, mp);
5470Sstevel@tonic-gate break;
5480Sstevel@tonic-gate
5490Sstevel@tonic-gate case M_FLUSH:
5500Sstevel@tonic-gate if (*mp->b_rptr & FLUSHW)
5510Sstevel@tonic-gate flushq(q, FLUSHALL);
5520Sstevel@tonic-gate
5530Sstevel@tonic-gate if (tmxp->muxq != NULL) {
5540Sstevel@tonic-gate putnext(tmxp->muxq, mp);
5550Sstevel@tonic-gate return (0);
5560Sstevel@tonic-gate }
5570Sstevel@tonic-gate
5580Sstevel@tonic-gate *mp->b_rptr &= ~FLUSHW;
5590Sstevel@tonic-gate if (*mp->b_rptr & FLUSHR)
5600Sstevel@tonic-gate qreply(q, mp);
5610Sstevel@tonic-gate else
5620Sstevel@tonic-gate freemsg(mp);
5630Sstevel@tonic-gate break;
5640Sstevel@tonic-gate
5650Sstevel@tonic-gate default:
5660Sstevel@tonic-gate cmn_err(CE_NOTE, "logdmuxuwput: received unexpected message"
5670Sstevel@tonic-gate " of type 0x%x", mp->b_datap->db_type);
5680Sstevel@tonic-gate freemsg(mp);
5690Sstevel@tonic-gate }
5700Sstevel@tonic-gate return (0);
5710Sstevel@tonic-gate }
5720Sstevel@tonic-gate
5730Sstevel@tonic-gate /*
5740Sstevel@tonic-gate * Upper write service routine
5750Sstevel@tonic-gate */
5760Sstevel@tonic-gate static int
logdmuxuwsrv(queue_t * q)5770Sstevel@tonic-gate logdmuxuwsrv(queue_t *q)
5780Sstevel@tonic-gate {
5790Sstevel@tonic-gate mblk_t *mp, *newmp;
5800Sstevel@tonic-gate queue_t *qp;
5810Sstevel@tonic-gate struct tmx *tmxp = q->q_ptr;
5820Sstevel@tonic-gate
5830Sstevel@tonic-gate while ((mp = getq(q)) != NULL) {
5840Sstevel@tonic-gate switch (mp->b_datap->db_type) {
5850Sstevel@tonic-gate case M_DATA:
5860Sstevel@tonic-gate if (!tmxp->isptm) {
5870Sstevel@tonic-gate if ((newmp = allocb(sizeof (char), BPRI_MED)) ==
5880Sstevel@tonic-gate NULL) {
5890Sstevel@tonic-gate recover(q, mp, sizeof (char));
5900Sstevel@tonic-gate return (0);
5910Sstevel@tonic-gate }
5920Sstevel@tonic-gate newmp->b_datap->db_type = M_CTL;
5930Sstevel@tonic-gate *newmp->b_wptr++ = M_CTL_MAGIC_NUMBER;
5940Sstevel@tonic-gate newmp->b_cont = mp;
5950Sstevel@tonic-gate mp = newmp;
5960Sstevel@tonic-gate }
5970Sstevel@tonic-gate /* FALLTHRU */
5980Sstevel@tonic-gate
5990Sstevel@tonic-gate case M_CTL:
6000Sstevel@tonic-gate case M_PROTO:
6010Sstevel@tonic-gate if (tmxp->muxq == NULL) {
6020Sstevel@tonic-gate merror(q, mp, EIO);
6030Sstevel@tonic-gate break;
6040Sstevel@tonic-gate }
6050Sstevel@tonic-gate qp = tmxp->muxq;
6060Sstevel@tonic-gate if (!canputnext(qp)) {
6070Sstevel@tonic-gate (void) putbq(q, mp);
6080Sstevel@tonic-gate return (0);
6090Sstevel@tonic-gate }
6100Sstevel@tonic-gate putnext(qp, mp);
6110Sstevel@tonic-gate break;
6120Sstevel@tonic-gate
6130Sstevel@tonic-gate
6140Sstevel@tonic-gate default:
6150Sstevel@tonic-gate cmn_err(CE_NOTE, "logdmuxuwsrv: received unexpected"
6160Sstevel@tonic-gate " message of type 0x%x", mp->b_datap->db_type);
6170Sstevel@tonic-gate freemsg(mp);
6180Sstevel@tonic-gate }
6190Sstevel@tonic-gate }
6200Sstevel@tonic-gate return (0);
6210Sstevel@tonic-gate }
6220Sstevel@tonic-gate
6230Sstevel@tonic-gate /*
6240Sstevel@tonic-gate * Logindmux lower put routine detects from which of the two lower queues
6250Sstevel@tonic-gate * the data needs to be read from and writes it out to its peer queue.
6260Sstevel@tonic-gate * For protocol, it detects M_CTL and sends its data to the daemon. Also,
6270Sstevel@tonic-gate * for ioctl and other types of messages, it lets the daemon handle it.
6280Sstevel@tonic-gate */
6290Sstevel@tonic-gate static int
logdmuxlrput(queue_t * q,mblk_t * mp)6300Sstevel@tonic-gate logdmuxlrput(queue_t *q, mblk_t *mp)
6310Sstevel@tonic-gate {
6320Sstevel@tonic-gate mblk_t *savemp;
6330Sstevel@tonic-gate queue_t *qp;
6340Sstevel@tonic-gate struct iocblk *ioc;
6350Sstevel@tonic-gate struct tmx *tmxp = q->q_ptr;
6360Sstevel@tonic-gate uchar_t flush;
6370Sstevel@tonic-gate uint_t *messagep;
6380Sstevel@tonic-gate unlinkinfo_t *unlinkinfop = tmxp->unlinkinfop;
6390Sstevel@tonic-gate
6400Sstevel@tonic-gate if (tmxp->muxq == NULL || tmxp->peerq == NULL) {
6410Sstevel@tonic-gate freemsg(mp);
6420Sstevel@tonic-gate return (0);
6430Sstevel@tonic-gate }
6440Sstevel@tonic-gate
6450Sstevel@tonic-gate /*
6460Sstevel@tonic-gate * If there's already a message on our queue and the incoming
6470Sstevel@tonic-gate * message is not of a high-priority, enqueue the message --
6480Sstevel@tonic-gate * but not if it's a logindmux protocol message.
6490Sstevel@tonic-gate */
6500Sstevel@tonic-gate if ((q->q_first != NULL) && (queclass(mp) < QPCTL) &&
6510Sstevel@tonic-gate (!LOGDMUX_PROTO_MBLK(mp))) {
6520Sstevel@tonic-gate (void) putq(q, mp);
6530Sstevel@tonic-gate return (0);
6540Sstevel@tonic-gate }
6550Sstevel@tonic-gate
6560Sstevel@tonic-gate switch (mp->b_datap->db_type) {
6570Sstevel@tonic-gate
6580Sstevel@tonic-gate case M_IOCTL:
6590Sstevel@tonic-gate ioc = (struct iocblk *)mp->b_rptr;
6600Sstevel@tonic-gate switch (ioc->ioc_cmd) {
6610Sstevel@tonic-gate
6620Sstevel@tonic-gate case TIOCSWINSZ:
6630Sstevel@tonic-gate case TCSETAF:
6640Sstevel@tonic-gate case TCSETSF:
6650Sstevel@tonic-gate case TCSETA:
6660Sstevel@tonic-gate case TCSETAW:
6670Sstevel@tonic-gate case TCSETS:
6680Sstevel@tonic-gate case TCSETSW:
6690Sstevel@tonic-gate case TCSBRK:
6700Sstevel@tonic-gate case TIOCSTI:
6710Sstevel@tonic-gate qp = tmxp->peerq;
6720Sstevel@tonic-gate break;
6730Sstevel@tonic-gate
6740Sstevel@tonic-gate default:
6750Sstevel@tonic-gate cmn_err(CE_NOTE, "logdmuxlrput: received unexpected"
6760Sstevel@tonic-gate " request for ioctl 0x%x", ioc->ioc_cmd);
6770Sstevel@tonic-gate
6780Sstevel@tonic-gate /* NAK unrecognized ioctl's. */
6790Sstevel@tonic-gate miocnak(q, mp, 0, 0);
6800Sstevel@tonic-gate return (0);
6810Sstevel@tonic-gate }
6820Sstevel@tonic-gate break;
6830Sstevel@tonic-gate
6840Sstevel@tonic-gate case M_DATA:
6850Sstevel@tonic-gate case M_HANGUP:
6860Sstevel@tonic-gate qp = tmxp->peerq;
6870Sstevel@tonic-gate break;
6880Sstevel@tonic-gate
6890Sstevel@tonic-gate case M_CTL:
6900Sstevel@tonic-gate /*
6910Sstevel@tonic-gate * The protocol messages that flow between the peers
6920Sstevel@tonic-gate * to implement the unlink functionality are M_CTLs
6930Sstevel@tonic-gate * which have the M_IOCTL/I_UNLINK mblk of the ioctl
6940Sstevel@tonic-gate * attached via b_cont. LOGDMUX_PROTO_MBLK() uses
6950Sstevel@tonic-gate * this to determine whether a particular M_CTL is a
6960Sstevel@tonic-gate * peer protocol message.
6970Sstevel@tonic-gate */
6980Sstevel@tonic-gate if (LOGDMUX_PROTO_MBLK(mp)) {
6990Sstevel@tonic-gate messagep = (uint_t *)mp->b_rptr;
7000Sstevel@tonic-gate
7010Sstevel@tonic-gate switch (*messagep) {
7020Sstevel@tonic-gate
7030Sstevel@tonic-gate case LOGDMUX_UNLINK_REQ:
7040Sstevel@tonic-gate /*
7050Sstevel@tonic-gate * We've received a message from our
7060Sstevel@tonic-gate * peer indicating that it wants to
7070Sstevel@tonic-gate * unlink.
7080Sstevel@tonic-gate */
7090Sstevel@tonic-gate *messagep = LOGDMUX_UNLINK_RESP;
7100Sstevel@tonic-gate qp = tmxp->peerq;
7110Sstevel@tonic-gate
7120Sstevel@tonic-gate mutex_enter(&logdmux_peerq_lock);
7130Sstevel@tonic-gate tmxp->peerq = NULL;
7140Sstevel@tonic-gate mutex_exit(&logdmux_peerq_lock);
7150Sstevel@tonic-gate
7160Sstevel@tonic-gate put(RD(qp), mp);
7170Sstevel@tonic-gate return (0);
7180Sstevel@tonic-gate
7190Sstevel@tonic-gate case LOGDMUX_UNLINK_RESP:
7200Sstevel@tonic-gate /*
7210Sstevel@tonic-gate * We've received a positive response
7220Sstevel@tonic-gate * from our peer to an earlier
7230Sstevel@tonic-gate * LOGDMUX_UNLINK_REQ that we sent.
7240Sstevel@tonic-gate * We can now carry on with the unlink.
7250Sstevel@tonic-gate */
7260Sstevel@tonic-gate qp = tmxp->rdq;
7270Sstevel@tonic-gate mutex_enter(&unlinkinfop->state_lock);
7280Sstevel@tonic-gate ASSERT(unlinkinfop->state ==
7290Sstevel@tonic-gate LOGDMUX_UNLINK_PENDING);
7300Sstevel@tonic-gate unlinkinfop->state = LOGDMUX_UNLINKED;
7310Sstevel@tonic-gate mutex_exit(&unlinkinfop->state_lock);
7320Sstevel@tonic-gate logdmux_finish_unlink(WR(qp), mp->b_cont);
7330Sstevel@tonic-gate return (0);
7340Sstevel@tonic-gate }
7350Sstevel@tonic-gate }
7360Sstevel@tonic-gate
7370Sstevel@tonic-gate qp = tmxp->rdq;
7380Sstevel@tonic-gate if (q->q_first != NULL || !canputnext(qp)) {
7390Sstevel@tonic-gate (void) putq(q, mp);
7400Sstevel@tonic-gate return (0);
7410Sstevel@tonic-gate }
7420Sstevel@tonic-gate if ((MBLKL(mp) == 1) && (*mp->b_rptr == M_CTL_MAGIC_NUMBER)) {
7430Sstevel@tonic-gate savemp = mp->b_cont;
7440Sstevel@tonic-gate freeb(mp);
7450Sstevel@tonic-gate mp = savemp;
7460Sstevel@tonic-gate }
7470Sstevel@tonic-gate putnext(qp, mp);
7480Sstevel@tonic-gate return (0);
7490Sstevel@tonic-gate
7500Sstevel@tonic-gate case M_IOCACK:
7510Sstevel@tonic-gate case M_IOCNAK:
7520Sstevel@tonic-gate case M_PROTO:
7530Sstevel@tonic-gate case M_PCPROTO:
7540Sstevel@tonic-gate case M_PCSIG:
7550Sstevel@tonic-gate case M_SETOPTS:
7560Sstevel@tonic-gate qp = tmxp->rdq;
7570Sstevel@tonic-gate break;
7580Sstevel@tonic-gate
7590Sstevel@tonic-gate case M_ERROR:
7600Sstevel@tonic-gate if (tmxp->isptm) {
7610Sstevel@tonic-gate /*
7620Sstevel@tonic-gate * This error is from ptm. We could tell TCP to
7630Sstevel@tonic-gate * shutdown the connection, but it's easier to just
7640Sstevel@tonic-gate * wait for the daemon to get SIGCHLD and close from
7650Sstevel@tonic-gate * above.
7660Sstevel@tonic-gate */
7670Sstevel@tonic-gate freemsg(mp);
7680Sstevel@tonic-gate return (0);
7690Sstevel@tonic-gate }
7700Sstevel@tonic-gate /*
7710Sstevel@tonic-gate * This is from TCP. Don't really know why we'd
7720Sstevel@tonic-gate * get this, but we have a pretty good idea what
7730Sstevel@tonic-gate * to do: Send M_HANGUP to the pty.
7740Sstevel@tonic-gate */
7750Sstevel@tonic-gate mp->b_datap->db_type = M_HANGUP;
7760Sstevel@tonic-gate mp->b_wptr = mp->b_rptr;
7770Sstevel@tonic-gate qp = tmxp->peerq;
7780Sstevel@tonic-gate break;
7790Sstevel@tonic-gate
7800Sstevel@tonic-gate case M_FLUSH:
7810Sstevel@tonic-gate if (*mp->b_rptr & FLUSHR)
7820Sstevel@tonic-gate flushq_dataonly(q);
7830Sstevel@tonic-gate
7840Sstevel@tonic-gate if (mp->b_flag & MSGMARK) {
7850Sstevel@tonic-gate /*
7860Sstevel@tonic-gate * This M_FLUSH has been marked by the module
7870Sstevel@tonic-gate * below as intended for the upper queue,
7880Sstevel@tonic-gate * not the peer queue.
7890Sstevel@tonic-gate */
7900Sstevel@tonic-gate qp = tmxp->rdq;
7910Sstevel@tonic-gate mp->b_flag &= ~MSGMARK;
7920Sstevel@tonic-gate } else {
7930Sstevel@tonic-gate /*
7940Sstevel@tonic-gate * Wrap this M_FLUSH through the mux.
7950Sstevel@tonic-gate * The FLUSHR and FLUSHW bits must be
7960Sstevel@tonic-gate * reversed.
7970Sstevel@tonic-gate */
7980Sstevel@tonic-gate qp = tmxp->peerq;
7990Sstevel@tonic-gate flush = *mp->b_rptr;
8000Sstevel@tonic-gate *mp->b_rptr &= ~(FLUSHR | FLUSHW);
8010Sstevel@tonic-gate if (flush & FLUSHW)
8020Sstevel@tonic-gate *mp->b_rptr |= FLUSHR;
8030Sstevel@tonic-gate if (flush & FLUSHR)
8040Sstevel@tonic-gate *mp->b_rptr |= FLUSHW;
8050Sstevel@tonic-gate }
8060Sstevel@tonic-gate break;
8070Sstevel@tonic-gate
8080Sstevel@tonic-gate case M_START:
8090Sstevel@tonic-gate case M_STOP:
8100Sstevel@tonic-gate case M_STARTI:
8110Sstevel@tonic-gate case M_STOPI:
8120Sstevel@tonic-gate freemsg(mp);
8130Sstevel@tonic-gate return (0);
8140Sstevel@tonic-gate
8150Sstevel@tonic-gate default:
8160Sstevel@tonic-gate cmn_err(CE_NOTE, "logdmuxlrput: received unexpected "
8170Sstevel@tonic-gate "message of type 0x%x", mp->b_datap->db_type);
8180Sstevel@tonic-gate freemsg(mp);
8190Sstevel@tonic-gate return (0);
8200Sstevel@tonic-gate }
8210Sstevel@tonic-gate if (queclass(mp) < QPCTL) {
8220Sstevel@tonic-gate if (q->q_first != NULL || !canputnext(qp)) {
8230Sstevel@tonic-gate (void) putq(q, mp);
8240Sstevel@tonic-gate return (0);
8250Sstevel@tonic-gate }
8260Sstevel@tonic-gate }
8270Sstevel@tonic-gate putnext(qp, mp);
8280Sstevel@tonic-gate return (0);
8290Sstevel@tonic-gate }
8300Sstevel@tonic-gate
8310Sstevel@tonic-gate /*
8320Sstevel@tonic-gate * Lower read service routine
8330Sstevel@tonic-gate */
8340Sstevel@tonic-gate static int
logdmuxlrsrv(queue_t * q)8350Sstevel@tonic-gate logdmuxlrsrv(queue_t *q)
8360Sstevel@tonic-gate {
8370Sstevel@tonic-gate mblk_t *mp, *savemp;
8380Sstevel@tonic-gate queue_t *qp;
8390Sstevel@tonic-gate struct iocblk *ioc;
8400Sstevel@tonic-gate struct tmx *tmxp = q->q_ptr;
8410Sstevel@tonic-gate
8420Sstevel@tonic-gate while ((mp = getq(q)) != NULL) {
8430Sstevel@tonic-gate if (tmxp->muxq == NULL || tmxp->peerq == NULL) {
8440Sstevel@tonic-gate freemsg(mp);
8450Sstevel@tonic-gate continue;
8460Sstevel@tonic-gate }
8470Sstevel@tonic-gate
8480Sstevel@tonic-gate switch (mp->b_datap->db_type) {
8490Sstevel@tonic-gate
8500Sstevel@tonic-gate case M_IOCTL:
8510Sstevel@tonic-gate ioc = (struct iocblk *)mp->b_rptr;
8520Sstevel@tonic-gate
8530Sstevel@tonic-gate switch (ioc->ioc_cmd) {
8540Sstevel@tonic-gate
8550Sstevel@tonic-gate case TIOCSWINSZ:
8560Sstevel@tonic-gate case TCSETAF:
8570Sstevel@tonic-gate case TCSETSF:
8580Sstevel@tonic-gate case TCSETA:
8590Sstevel@tonic-gate case TCSETAW:
8600Sstevel@tonic-gate case TCSETS:
8610Sstevel@tonic-gate case TCSETSW:
8620Sstevel@tonic-gate case TCSBRK:
8630Sstevel@tonic-gate case TIOCSTI:
8640Sstevel@tonic-gate qp = tmxp->peerq;
8650Sstevel@tonic-gate break;
8660Sstevel@tonic-gate
8670Sstevel@tonic-gate default:
8680Sstevel@tonic-gate cmn_err(CE_NOTE, "logdmuxlrsrv: received "
8690Sstevel@tonic-gate "unexpected request for ioctl 0x%x",
8700Sstevel@tonic-gate ioc->ioc_cmd);
8710Sstevel@tonic-gate
8720Sstevel@tonic-gate /* NAK unrecognized ioctl's. */
8730Sstevel@tonic-gate miocnak(q, mp, 0, 0);
8740Sstevel@tonic-gate continue;
8750Sstevel@tonic-gate }
8760Sstevel@tonic-gate break;
8770Sstevel@tonic-gate
8780Sstevel@tonic-gate case M_DATA:
8790Sstevel@tonic-gate case M_HANGUP:
8800Sstevel@tonic-gate qp = tmxp->peerq;
8810Sstevel@tonic-gate break;
8820Sstevel@tonic-gate
8830Sstevel@tonic-gate case M_CTL:
8840Sstevel@tonic-gate qp = tmxp->rdq;
8850Sstevel@tonic-gate if (!canputnext(qp)) {
8860Sstevel@tonic-gate (void) putbq(q, mp);
8870Sstevel@tonic-gate return (0);
8880Sstevel@tonic-gate }
8890Sstevel@tonic-gate if (MBLKL(mp) == 1 &&
8900Sstevel@tonic-gate (*mp->b_rptr == M_CTL_MAGIC_NUMBER)) {
8910Sstevel@tonic-gate savemp = mp->b_cont;
8920Sstevel@tonic-gate freeb(mp);
8930Sstevel@tonic-gate mp = savemp;
8940Sstevel@tonic-gate }
8950Sstevel@tonic-gate putnext(qp, mp);
8960Sstevel@tonic-gate continue;
8970Sstevel@tonic-gate
8980Sstevel@tonic-gate case M_PROTO:
8990Sstevel@tonic-gate case M_SETOPTS:
9000Sstevel@tonic-gate qp = tmxp->rdq;
9010Sstevel@tonic-gate break;
9020Sstevel@tonic-gate
9030Sstevel@tonic-gate default:
9040Sstevel@tonic-gate cmn_err(CE_NOTE, "logdmuxlrsrv: received unexpected "
9050Sstevel@tonic-gate "message of type 0x%x", mp->b_datap->db_type);
9060Sstevel@tonic-gate freemsg(mp);
9070Sstevel@tonic-gate continue;
9080Sstevel@tonic-gate }
9090Sstevel@tonic-gate ASSERT(queclass(mp) < QPCTL);
9100Sstevel@tonic-gate if (!canputnext(qp)) {
9110Sstevel@tonic-gate (void) putbq(q, mp);
9120Sstevel@tonic-gate return (0);
9130Sstevel@tonic-gate }
9140Sstevel@tonic-gate putnext(qp, mp);
9150Sstevel@tonic-gate }
9160Sstevel@tonic-gate return (0);
9170Sstevel@tonic-gate }
9180Sstevel@tonic-gate
9190Sstevel@tonic-gate /*
9200Sstevel@tonic-gate * Lower side write service procedure. No messages are ever placed on
9210Sstevel@tonic-gate * the write queue here, this just back-enables all of the upper side
9220Sstevel@tonic-gate * write service procedures.
9230Sstevel@tonic-gate */
9240Sstevel@tonic-gate static int
logdmuxlwsrv(queue_t * q)9250Sstevel@tonic-gate logdmuxlwsrv(queue_t *q)
9260Sstevel@tonic-gate {
9270Sstevel@tonic-gate struct tmx *tmxp = q->q_ptr;
9280Sstevel@tonic-gate
9290Sstevel@tonic-gate /*
9300Sstevel@tonic-gate * Qenable upper write queue and find out which lower
9310Sstevel@tonic-gate * queue needs to be restarted with flow control.
9320Sstevel@tonic-gate * Qenable the peer queue so canputnext will
9330Sstevel@tonic-gate * succeed on next call to logdmuxlrput.
9340Sstevel@tonic-gate */
9350Sstevel@tonic-gate qenable(WR(tmxp->rdq));
9360Sstevel@tonic-gate
9370Sstevel@tonic-gate mutex_enter(&logdmux_peerq_lock);
9380Sstevel@tonic-gate if (tmxp->peerq != NULL)
9390Sstevel@tonic-gate qenable(RD(tmxp->peerq));
9400Sstevel@tonic-gate mutex_exit(&logdmux_peerq_lock);
9410Sstevel@tonic-gate
9420Sstevel@tonic-gate return (0);
9430Sstevel@tonic-gate }
9440Sstevel@tonic-gate
9450Sstevel@tonic-gate /*
9460Sstevel@tonic-gate * This routine does I_LINK operation.
9470Sstevel@tonic-gate */
9480Sstevel@tonic-gate static void
logdmuxlink(queue_t * q,mblk_t * mp)9490Sstevel@tonic-gate logdmuxlink(queue_t *q, mblk_t *mp)
9500Sstevel@tonic-gate {
9510Sstevel@tonic-gate struct tmx *tmxp = q->q_ptr;
9520Sstevel@tonic-gate struct linkblk *lp = (struct linkblk *)mp->b_cont->b_rptr;
9530Sstevel@tonic-gate
9540Sstevel@tonic-gate /*
9550Sstevel@tonic-gate * Fail if we're already linked.
9560Sstevel@tonic-gate */
9570Sstevel@tonic-gate if (tmxp->muxq != NULL) {
9580Sstevel@tonic-gate miocnak(q, mp, 0, EINVAL);
9590Sstevel@tonic-gate return;
9600Sstevel@tonic-gate }
9610Sstevel@tonic-gate
9620Sstevel@tonic-gate tmxp->muxq = lp->l_qbot;
9630Sstevel@tonic-gate tmxp->muxq->q_ptr = tmxp;
9640Sstevel@tonic-gate RD(tmxp->muxq)->q_ptr = tmxp;
9650Sstevel@tonic-gate
9660Sstevel@tonic-gate miocack(q, mp, 0, 0);
9670Sstevel@tonic-gate }
9680Sstevel@tonic-gate
9690Sstevel@tonic-gate /*
9700Sstevel@tonic-gate * logdmuxunlink() is called from logdmuxuwput() and is the first of two
9710Sstevel@tonic-gate * functions which process an I_UNLINK ioctl. logdmuxunlink() will determine
9720Sstevel@tonic-gate * the state of logindmux peer linkage and, based on this, control when the
9730Sstevel@tonic-gate * second function, logdmux_finish_unlink(), is called. It's
9740Sstevel@tonic-gate * logdmux_finish_unlink() that's sending the M_IOCACK upstream and
9750Sstevel@tonic-gate * resetting the link state.
9760Sstevel@tonic-gate */
9770Sstevel@tonic-gate static void
logdmuxunlink(queue_t * q,mblk_t * mp)9780Sstevel@tonic-gate logdmuxunlink(queue_t *q, mblk_t *mp)
9790Sstevel@tonic-gate {
9800Sstevel@tonic-gate struct tmx *tmxp = q->q_ptr;
9810Sstevel@tonic-gate unlinkinfo_t *unlinkinfop;
9820Sstevel@tonic-gate
9830Sstevel@tonic-gate /*
9840Sstevel@tonic-gate * If we don't have a peer, just unlink. Note that this check needs
9850Sstevel@tonic-gate * to be done under logdmux_qexch_lock to prevent racing with
9860Sstevel@tonic-gate * LOGDMX_IOC_QEXCHANGE, and we *must* set muxq to NULL prior to
9870Sstevel@tonic-gate * releasing the lock so that LOGDMX_IOC_QEXCHANGE will not consider
9880Sstevel@tonic-gate * us as a possible peer anymore (if it already considers us to be a
9890Sstevel@tonic-gate * peer, then unlinkinfop will not be NULL) -- NULLing muxq precludes
9900Sstevel@tonic-gate * use of logdmux_finish_unlink() here.
9910Sstevel@tonic-gate */
9920Sstevel@tonic-gate mutex_enter(&logdmux_qexch_lock);
9930Sstevel@tonic-gate unlinkinfop = tmxp->unlinkinfop;
9940Sstevel@tonic-gate if (unlinkinfop == NULL) {
9950Sstevel@tonic-gate ASSERT(tmxp->peerq == NULL);
9960Sstevel@tonic-gate tmxp->muxq = NULL;
9970Sstevel@tonic-gate mutex_exit(&logdmux_qexch_lock);
9980Sstevel@tonic-gate miocack(q, mp, 0, 0);
9990Sstevel@tonic-gate return;
10000Sstevel@tonic-gate }
10010Sstevel@tonic-gate mutex_exit(&logdmux_qexch_lock);
10020Sstevel@tonic-gate
10030Sstevel@tonic-gate mutex_enter(&unlinkinfop->state_lock);
10040Sstevel@tonic-gate
10050Sstevel@tonic-gate switch (unlinkinfop->state) {
10060Sstevel@tonic-gate
10070Sstevel@tonic-gate case LOGDMUX_LINKED:
10080Sstevel@tonic-gate /*
10090Sstevel@tonic-gate * We're the first instance to process an I_UNLINK --
10100Sstevel@tonic-gate * ie, the peer instance is still there. We'll change
10110Sstevel@tonic-gate * the state so that only one instance is executing an
10120Sstevel@tonic-gate * I_UNLINK at any one time.
10130Sstevel@tonic-gate */
10140Sstevel@tonic-gate unlinkinfop->state = LOGDMUX_UNLINK_PENDING;
10150Sstevel@tonic-gate mutex_exit(&unlinkinfop->state_lock);
10160Sstevel@tonic-gate /*
10170Sstevel@tonic-gate * Attach the original M_IOCTL message to a
10180Sstevel@tonic-gate * LOGDMUX_UNLINK_REQ message and send it to our peer to
10190Sstevel@tonic-gate * tell it to unlink from us. When it has completed the
10200Sstevel@tonic-gate * task, it will send us a LOGDMUX_UNLINK_RESP message
10210Sstevel@tonic-gate * with the original M_IOCTL still attached, which will be
10220Sstevel@tonic-gate * processed in our logdmuxlrput(). At that point, we will
10230Sstevel@tonic-gate * call logdmux_finish_unlink() to complete the unlink
10240Sstevel@tonic-gate * operation using the attached M_IOCTL.
10250Sstevel@tonic-gate */
10260Sstevel@tonic-gate unlinkinfop->prot_mp->b_cont = mp;
10270Sstevel@tonic-gate /*
10280Sstevel@tonic-gate * Put the M_CTL directly to the peer's lower RQ.
10290Sstevel@tonic-gate */
10300Sstevel@tonic-gate put(RD(tmxp->peerq), unlinkinfop->prot_mp);
10310Sstevel@tonic-gate break;
10320Sstevel@tonic-gate
10330Sstevel@tonic-gate case LOGDMUX_UNLINK_PENDING:
10340Sstevel@tonic-gate mutex_exit(&unlinkinfop->state_lock);
10350Sstevel@tonic-gate /*
10360Sstevel@tonic-gate * Our peer is actively processing an I_UNLINK itself.
10370Sstevel@tonic-gate * We have to wait for the peer to complete and we use
10380Sstevel@tonic-gate * qtimeout as a way to poll for its completion.
10390Sstevel@tonic-gate * We save a reference to our mblk so that we can send
10400Sstevel@tonic-gate * it upstream once our peer is done.
10410Sstevel@tonic-gate */
10420Sstevel@tonic-gate tmxp->unlink_mp = mp;
10430Sstevel@tonic-gate tmxp->utimoutid = qtimeout(q, logdmux_unlink_timer, q,
10440Sstevel@tonic-gate drv_usectohz(LOGDMUX_POLL_WAIT));
10450Sstevel@tonic-gate break;
10460Sstevel@tonic-gate
10470Sstevel@tonic-gate case LOGDMUX_UNLINKED:
10480Sstevel@tonic-gate /*
10490Sstevel@tonic-gate * Our peer is no longer linked so we can proceed.
10500Sstevel@tonic-gate */
10510Sstevel@tonic-gate mutex_exit(&unlinkinfop->state_lock);
10520Sstevel@tonic-gate mutex_destroy(&unlinkinfop->state_lock);
10530Sstevel@tonic-gate freeb(unlinkinfop->prot_mp);
10540Sstevel@tonic-gate kmem_free(unlinkinfop, sizeof (unlinkinfo_t));
10550Sstevel@tonic-gate logdmux_finish_unlink(q, mp);
10560Sstevel@tonic-gate break;
10570Sstevel@tonic-gate
10580Sstevel@tonic-gate default:
10590Sstevel@tonic-gate mutex_exit(&unlinkinfop->state_lock);
10600Sstevel@tonic-gate cmn_err(CE_PANIC,
10610Sstevel@tonic-gate "logdmuxunlink: peer linkage is in an unrecognized state");
10620Sstevel@tonic-gate break;
10630Sstevel@tonic-gate }
10640Sstevel@tonic-gate }
10650Sstevel@tonic-gate
10660Sstevel@tonic-gate /*
10670Sstevel@tonic-gate * Finish the unlink operation. Note that no locks should be held since
10680Sstevel@tonic-gate * this routine calls into other queues.
10690Sstevel@tonic-gate */
10700Sstevel@tonic-gate static void
logdmux_finish_unlink(queue_t * q,mblk_t * unlink_mp)10710Sstevel@tonic-gate logdmux_finish_unlink(queue_t *q, mblk_t *unlink_mp)
10720Sstevel@tonic-gate {
10730Sstevel@tonic-gate struct tmx *tmxp = q->q_ptr;
10740Sstevel@tonic-gate mblk_t *mp;
10750Sstevel@tonic-gate
10760Sstevel@tonic-gate /*
10770Sstevel@tonic-gate * Flush any write side data downstream.
10780Sstevel@tonic-gate */
10790Sstevel@tonic-gate while ((mp = getq(WR(q))) != NULL)
10800Sstevel@tonic-gate putnext(tmxp->muxq, mp);
10810Sstevel@tonic-gate
10820Sstevel@tonic-gate /*
10830Sstevel@tonic-gate * Note that we do not NULL out q_ptr since another thread (e.g., a
10840Sstevel@tonic-gate * STREAMS service thread) might call logdmuxlrput() between the time
10850Sstevel@tonic-gate * we exit the logindmux perimeter and the time the STREAMS framework
10860Sstevel@tonic-gate * resets q_ptr to stdata (since muxq is set to NULL, any messages
10870Sstevel@tonic-gate * will just be discarded).
10880Sstevel@tonic-gate */
10890Sstevel@tonic-gate tmxp->muxq = NULL;
10900Sstevel@tonic-gate tmxp->unlinkinfop = NULL;
10910Sstevel@tonic-gate tmxp->peerq = NULL;
10920Sstevel@tonic-gate miocack(q, unlink_mp, 0, 0);
10930Sstevel@tonic-gate }
10940Sstevel@tonic-gate
10950Sstevel@tonic-gate /*
10960Sstevel@tonic-gate * logdmux_unlink_timer() is executed by qtimeout(). This function will
10970Sstevel@tonic-gate * check unlinkinfop->state to determine whether the peer has completed
10980Sstevel@tonic-gate * its I_UNLINK. If it hasn't, we use qtimeout() to initiate another poll.
10990Sstevel@tonic-gate */
11000Sstevel@tonic-gate static void
logdmux_unlink_timer(void * arg)11010Sstevel@tonic-gate logdmux_unlink_timer(void *arg)
11020Sstevel@tonic-gate {
11030Sstevel@tonic-gate queue_t *q = arg;
11040Sstevel@tonic-gate struct tmx *tmxp = q->q_ptr;
11050Sstevel@tonic-gate unlinkinfo_t *unlinkinfop = tmxp->unlinkinfop;
11060Sstevel@tonic-gate
11070Sstevel@tonic-gate tmxp->utimoutid = 0;
11080Sstevel@tonic-gate
11090Sstevel@tonic-gate mutex_enter(&unlinkinfop->state_lock);
11100Sstevel@tonic-gate
11110Sstevel@tonic-gate if (unlinkinfop->state != LOGDMUX_UNLINKED) {
11120Sstevel@tonic-gate ASSERT(unlinkinfop->state == LOGDMUX_UNLINK_PENDING);
11130Sstevel@tonic-gate mutex_exit(&unlinkinfop->state_lock);
11140Sstevel@tonic-gate /*
11150Sstevel@tonic-gate * We need to wait longer for our peer to complete.
11160Sstevel@tonic-gate */
11170Sstevel@tonic-gate tmxp->utimoutid = qtimeout(q, logdmux_unlink_timer, q,
11180Sstevel@tonic-gate drv_usectohz(LOGDMUX_POLL_WAIT));
11190Sstevel@tonic-gate } else {
11200Sstevel@tonic-gate /*
11210Sstevel@tonic-gate * Our peer is no longer linked so we can proceed with
11220Sstevel@tonic-gate * the cleanup.
11230Sstevel@tonic-gate */
11240Sstevel@tonic-gate mutex_exit(&unlinkinfop->state_lock);
11250Sstevel@tonic-gate mutex_destroy(&unlinkinfop->state_lock);
11260Sstevel@tonic-gate freeb(unlinkinfop->prot_mp);
11270Sstevel@tonic-gate kmem_free(unlinkinfop, sizeof (unlinkinfo_t));
11280Sstevel@tonic-gate logdmux_finish_unlink(q, tmxp->unlink_mp);
11290Sstevel@tonic-gate }
11300Sstevel@tonic-gate }
11310Sstevel@tonic-gate
11320Sstevel@tonic-gate static void
logdmux_timer(void * arg)11330Sstevel@tonic-gate logdmux_timer(void *arg)
11340Sstevel@tonic-gate {
11350Sstevel@tonic-gate queue_t *q = arg;
11360Sstevel@tonic-gate struct tmx *tmxp = q->q_ptr;
11370Sstevel@tonic-gate
11380Sstevel@tonic-gate ASSERT(tmxp != NULL);
11390Sstevel@tonic-gate
11400Sstevel@tonic-gate if (q->q_flag & QREADR) {
11410Sstevel@tonic-gate ASSERT(tmxp->rtimoutid != 0);
11420Sstevel@tonic-gate tmxp->rtimoutid = 0;
11430Sstevel@tonic-gate } else {
11440Sstevel@tonic-gate ASSERT(tmxp->wtimoutid != 0);
11450Sstevel@tonic-gate tmxp->wtimoutid = 0;
11460Sstevel@tonic-gate }
11470Sstevel@tonic-gate enableok(q);
11480Sstevel@tonic-gate qenable(q);
11490Sstevel@tonic-gate }
11500Sstevel@tonic-gate
11510Sstevel@tonic-gate static void
logdmux_buffer(void * arg)11520Sstevel@tonic-gate logdmux_buffer(void *arg)
11530Sstevel@tonic-gate {
11540Sstevel@tonic-gate queue_t *q = arg;
11550Sstevel@tonic-gate struct tmx *tmxp = q->q_ptr;
11560Sstevel@tonic-gate
11570Sstevel@tonic-gate ASSERT(tmxp != NULL);
11580Sstevel@tonic-gate
11590Sstevel@tonic-gate if (q->q_flag & QREADR) {
11600Sstevel@tonic-gate ASSERT(tmxp->rbufcid != 0);
11610Sstevel@tonic-gate tmxp->rbufcid = 0;
11620Sstevel@tonic-gate } else {
11630Sstevel@tonic-gate ASSERT(tmxp->wbufcid != 0);
11640Sstevel@tonic-gate tmxp->wbufcid = 0;
11650Sstevel@tonic-gate }
11660Sstevel@tonic-gate enableok(q);
11670Sstevel@tonic-gate qenable(q);
11680Sstevel@tonic-gate }
11690Sstevel@tonic-gate
11700Sstevel@tonic-gate static void
recover(queue_t * q,mblk_t * mp,size_t size)11710Sstevel@tonic-gate recover(queue_t *q, mblk_t *mp, size_t size)
11720Sstevel@tonic-gate {
11730Sstevel@tonic-gate timeout_id_t tid;
11740Sstevel@tonic-gate bufcall_id_t bid;
11750Sstevel@tonic-gate struct tmx *tmxp = q->q_ptr;
11760Sstevel@tonic-gate
11770Sstevel@tonic-gate /*
11780Sstevel@tonic-gate * Avoid re-enabling the queue.
11790Sstevel@tonic-gate */
11800Sstevel@tonic-gate ASSERT(queclass(mp) < QPCTL);
11810Sstevel@tonic-gate ASSERT(WR(q)->q_next == NULL); /* Called from upper queue only */
11820Sstevel@tonic-gate noenable(q);
11830Sstevel@tonic-gate (void) putbq(q, mp);
11840Sstevel@tonic-gate
11850Sstevel@tonic-gate /*
11860Sstevel@tonic-gate * Make sure there is at most one outstanding request per queue.
11870Sstevel@tonic-gate */
11880Sstevel@tonic-gate if (q->q_flag & QREADR) {
11890Sstevel@tonic-gate if (tmxp->rtimoutid != 0 || tmxp->rbufcid != 0)
11900Sstevel@tonic-gate return;
11910Sstevel@tonic-gate } else {
11920Sstevel@tonic-gate if (tmxp->wtimoutid != 0 || tmxp->wbufcid != 0)
11930Sstevel@tonic-gate return;
11940Sstevel@tonic-gate }
11950Sstevel@tonic-gate if (!(bid = qbufcall(RD(q), size, BPRI_MED, logdmux_buffer, q))) {
11960Sstevel@tonic-gate tid = qtimeout(RD(q), logdmux_timer, q, drv_usectohz(SIMWAIT));
11970Sstevel@tonic-gate if (q->q_flag & QREADR)
11980Sstevel@tonic-gate tmxp->rtimoutid = tid;
11990Sstevel@tonic-gate else
12000Sstevel@tonic-gate tmxp->wtimoutid = tid;
12010Sstevel@tonic-gate } else {
12020Sstevel@tonic-gate if (q->q_flag & QREADR)
12030Sstevel@tonic-gate tmxp->rbufcid = bid;
12040Sstevel@tonic-gate else
12050Sstevel@tonic-gate tmxp->wbufcid = bid;
12060Sstevel@tonic-gate }
12070Sstevel@tonic-gate }
12080Sstevel@tonic-gate
12090Sstevel@tonic-gate static void
flushq_dataonly(queue_t * q)12100Sstevel@tonic-gate flushq_dataonly(queue_t *q)
12110Sstevel@tonic-gate {
12120Sstevel@tonic-gate mblk_t *mp, *nmp;
12130Sstevel@tonic-gate
12140Sstevel@tonic-gate /*
12150Sstevel@tonic-gate * Since we are already in the perimeter, and we are not a put-shared
12160Sstevel@tonic-gate * perimeter, we don't need to freeze the stream or anything to
12170Sstevel@tonic-gate * be ensured of exclusivity.
12180Sstevel@tonic-gate */
12190Sstevel@tonic-gate mp = q->q_first;
12200Sstevel@tonic-gate while (mp != NULL) {
12210Sstevel@tonic-gate if (mp->b_datap->db_type == M_DATA) {
12220Sstevel@tonic-gate nmp = mp->b_next;
12230Sstevel@tonic-gate rmvq(q, mp);
12240Sstevel@tonic-gate freemsg(mp);
12250Sstevel@tonic-gate mp = nmp;
12260Sstevel@tonic-gate } else {
12270Sstevel@tonic-gate mp = mp->b_next;
12280Sstevel@tonic-gate }
12290Sstevel@tonic-gate }
12300Sstevel@tonic-gate }
12310Sstevel@tonic-gate
12320Sstevel@tonic-gate /*
12330Sstevel@tonic-gate * logdmux_alloc_unlinkinfo() is called from logdmuxuwput() during the
12340Sstevel@tonic-gate * processing of a LOGDMX_IOC_QEXCHANGE ioctl() to allocate the
12350Sstevel@tonic-gate * unlinkinfo_t which is needed during the processing of an I_UNLINK.
12360Sstevel@tonic-gate */
12370Sstevel@tonic-gate static int
logdmux_alloc_unlinkinfo(struct tmx * t0,struct tmx * t1)12380Sstevel@tonic-gate logdmux_alloc_unlinkinfo(struct tmx *t0, struct tmx *t1)
12390Sstevel@tonic-gate {
12400Sstevel@tonic-gate unlinkinfo_t *p;
12410Sstevel@tonic-gate uint_t *messagep;
12420Sstevel@tonic-gate
12430Sstevel@tonic-gate if ((p = kmem_zalloc(sizeof (unlinkinfo_t), KM_NOSLEEP)) == NULL)
12440Sstevel@tonic-gate return (ENOSR);
12450Sstevel@tonic-gate
12460Sstevel@tonic-gate if ((p->prot_mp = allocb(sizeof (uint_t), BPRI_MED)) == NULL) {
12470Sstevel@tonic-gate kmem_free(p, sizeof (unlinkinfo_t));
12480Sstevel@tonic-gate return (ENOSR);
12490Sstevel@tonic-gate }
12500Sstevel@tonic-gate
12510Sstevel@tonic-gate DB_TYPE(p->prot_mp) = M_CTL;
12520Sstevel@tonic-gate messagep = (uint_t *)p->prot_mp->b_wptr;
12530Sstevel@tonic-gate *messagep = LOGDMUX_UNLINK_REQ;
12540Sstevel@tonic-gate p->prot_mp->b_wptr += sizeof (*messagep);
12550Sstevel@tonic-gate p->state = LOGDMUX_LINKED;
12560Sstevel@tonic-gate mutex_init(&p->state_lock, NULL, MUTEX_DRIVER, NULL);
12570Sstevel@tonic-gate
12580Sstevel@tonic-gate t0->unlinkinfop = t1->unlinkinfop = p;
12590Sstevel@tonic-gate
12600Sstevel@tonic-gate return (0);
12610Sstevel@tonic-gate }
1262