1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate /* 30*7c478bd9Sstevel@tonic-gate * Description: logindmux.c 31*7c478bd9Sstevel@tonic-gate * 32*7c478bd9Sstevel@tonic-gate * The logindmux driver is used with login modules (like telmod/rlmod). 33*7c478bd9Sstevel@tonic-gate * This is a 1x1 cloning mux and two of these muxes are used. The lower link 34*7c478bd9Sstevel@tonic-gate * of one of the muxes receives input from net and the lower link of the 35*7c478bd9Sstevel@tonic-gate * other mux receives input from pseudo terminal subsystem. 36*7c478bd9Sstevel@tonic-gate * 37*7c478bd9Sstevel@tonic-gate * The logdmux_qexch_lock mutex manages the race between LOGDMX_IOC_QEXCHANGE, 38*7c478bd9Sstevel@tonic-gate * logdmuxunlink() and logdmuxclose(), so that the instance selected as a peer 39*7c478bd9Sstevel@tonic-gate * in LOGDMX_IOC_QEXCHANGE cannot be unlinked or closed until the qexchange 40*7c478bd9Sstevel@tonic-gate * is complete; see the inline comments in the code for details. 41*7c478bd9Sstevel@tonic-gate * 42*7c478bd9Sstevel@tonic-gate * The logdmux_peerq_lock mutex manages the race between logdmuxlwsrv() and 43*7c478bd9Sstevel@tonic-gate * logdmuxlrput() (when null'ing tmxp->peerq during LOGDMUX_UNLINK_REQ 44*7c478bd9Sstevel@tonic-gate * processing). 45*7c478bd9Sstevel@tonic-gate * 46*7c478bd9Sstevel@tonic-gate * The logdmux_minor_lock mutex serializes the growth of logdmux_minor_arena 47*7c478bd9Sstevel@tonic-gate * (the arena is grown gradually rather than allocated all at once so that 48*7c478bd9Sstevel@tonic-gate * minor numbers are recycled sooner; for simplicity it is never shrunk). 49*7c478bd9Sstevel@tonic-gate * 50*7c478bd9Sstevel@tonic-gate * The unlink operation is implemented using protocol messages that flow 51*7c478bd9Sstevel@tonic-gate * between the two logindmux peer instances. The instance processing the 52*7c478bd9Sstevel@tonic-gate * I_UNLINK ioctl will send a LOGDMUX_UNLINK_REQ protocol message to its 53*7c478bd9Sstevel@tonic-gate * peer to indicate that it wishes to unlink; the peer will process this 54*7c478bd9Sstevel@tonic-gate * message in its lrput, null its tmxp->peerq and then send a 55*7c478bd9Sstevel@tonic-gate * LOGDMUX_UNLINK_RESP protocol message in reply to indicate that the 56*7c478bd9Sstevel@tonic-gate * unlink can proceed; having received the reply in its lrput, the 57*7c478bd9Sstevel@tonic-gate * instance processing the I_UNLINK can then continue. To ensure that only 58*7c478bd9Sstevel@tonic-gate * one of the peer instances will be actively processing an I_UNLINK at 59*7c478bd9Sstevel@tonic-gate * any one time, a single structure (an unlinkinfo_t containing a mutex, 60*7c478bd9Sstevel@tonic-gate * state variable and pointer to an M_CTL mblk) is allocated during 61*7c478bd9Sstevel@tonic-gate * the processing of the LOGDMX_IOC_QEXCHANGE ioctl. The two instances, if 62*7c478bd9Sstevel@tonic-gate * trying to unlink simultaneously, will race to get control of this 63*7c478bd9Sstevel@tonic-gate * structure which contains the resources necessary to process the 64*7c478bd9Sstevel@tonic-gate * I_UNLINK. The instance that wins this race will be able to continue 65*7c478bd9Sstevel@tonic-gate * with the unlink whilst the other instance will be obliged to wait. 66*7c478bd9Sstevel@tonic-gate */ 67*7c478bd9Sstevel@tonic-gate 68*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 69*7c478bd9Sstevel@tonic-gate #include <sys/param.h> 70*7c478bd9Sstevel@tonic-gate #include <sys/errno.h> 71*7c478bd9Sstevel@tonic-gate #include <sys/debug.h> 72*7c478bd9Sstevel@tonic-gate #include <sys/stropts.h> 73*7c478bd9Sstevel@tonic-gate #include <sys/stream.h> 74*7c478bd9Sstevel@tonic-gate #include <sys/logindmux.h> 75*7c478bd9Sstevel@tonic-gate #include <sys/logindmux_impl.h> 76*7c478bd9Sstevel@tonic-gate #include <sys/stat.h> 77*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 78*7c478bd9Sstevel@tonic-gate #include <sys/vmem.h> 79*7c478bd9Sstevel@tonic-gate #include <sys/strsun.h> 80*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 81*7c478bd9Sstevel@tonic-gate #include <sys/mkdev.h> 82*7c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 83*7c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 84*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 85*7c478bd9Sstevel@tonic-gate #include <sys/termios.h> 86*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 87*7c478bd9Sstevel@tonic-gate 88*7c478bd9Sstevel@tonic-gate static int logdmuxopen(queue_t *, dev_t *, int, int, cred_t *); 89*7c478bd9Sstevel@tonic-gate static int logdmuxclose(queue_t *, int, cred_t *); 90*7c478bd9Sstevel@tonic-gate static int logdmuxursrv(queue_t *); 91*7c478bd9Sstevel@tonic-gate static int logdmuxuwput(queue_t *, mblk_t *); 92*7c478bd9Sstevel@tonic-gate static int logdmuxlrput(queue_t *, mblk_t *); 93*7c478bd9Sstevel@tonic-gate static int logdmuxlrsrv(queue_t *); 94*7c478bd9Sstevel@tonic-gate static int logdmuxlwsrv(queue_t *); 95*7c478bd9Sstevel@tonic-gate static int logdmuxuwsrv(queue_t *); 96*7c478bd9Sstevel@tonic-gate static int logdmux_alloc_unlinkinfo(struct tmx *, struct tmx *); 97*7c478bd9Sstevel@tonic-gate 98*7c478bd9Sstevel@tonic-gate static void logdmuxlink(queue_t *, mblk_t *); 99*7c478bd9Sstevel@tonic-gate static void logdmuxunlink(queue_t *, mblk_t *); 100*7c478bd9Sstevel@tonic-gate static void logdmux_finish_unlink(queue_t *, mblk_t *); 101*7c478bd9Sstevel@tonic-gate static void logdmux_unlink_timer(void *arg); 102*7c478bd9Sstevel@tonic-gate static void recover(queue_t *, mblk_t *, size_t); 103*7c478bd9Sstevel@tonic-gate static void flushq_dataonly(queue_t *); 104*7c478bd9Sstevel@tonic-gate 105*7c478bd9Sstevel@tonic-gate static kmutex_t logdmux_qexch_lock; 106*7c478bd9Sstevel@tonic-gate static kmutex_t logdmux_peerq_lock; 107*7c478bd9Sstevel@tonic-gate static kmutex_t logdmux_minor_lock; 108*7c478bd9Sstevel@tonic-gate static minor_t logdmux_maxminor = 256; /* grown as necessary */ 109*7c478bd9Sstevel@tonic-gate static vmem_t *logdmux_minor_arena; 110*7c478bd9Sstevel@tonic-gate static void *logdmux_statep; 111*7c478bd9Sstevel@tonic-gate 112*7c478bd9Sstevel@tonic-gate static struct module_info logdmuxm_info = { 113*7c478bd9Sstevel@tonic-gate LOGDMX_ID, 114*7c478bd9Sstevel@tonic-gate "logindmux", 115*7c478bd9Sstevel@tonic-gate 0, 116*7c478bd9Sstevel@tonic-gate 256, 117*7c478bd9Sstevel@tonic-gate 512, 118*7c478bd9Sstevel@tonic-gate 256 119*7c478bd9Sstevel@tonic-gate }; 120*7c478bd9Sstevel@tonic-gate 121*7c478bd9Sstevel@tonic-gate static struct qinit logdmuxurinit = { 122*7c478bd9Sstevel@tonic-gate NULL, 123*7c478bd9Sstevel@tonic-gate logdmuxursrv, 124*7c478bd9Sstevel@tonic-gate logdmuxopen, 125*7c478bd9Sstevel@tonic-gate logdmuxclose, 126*7c478bd9Sstevel@tonic-gate NULL, 127*7c478bd9Sstevel@tonic-gate &logdmuxm_info 128*7c478bd9Sstevel@tonic-gate }; 129*7c478bd9Sstevel@tonic-gate 130*7c478bd9Sstevel@tonic-gate static struct qinit logdmuxuwinit = { 131*7c478bd9Sstevel@tonic-gate logdmuxuwput, 132*7c478bd9Sstevel@tonic-gate logdmuxuwsrv, 133*7c478bd9Sstevel@tonic-gate NULL, 134*7c478bd9Sstevel@tonic-gate NULL, 135*7c478bd9Sstevel@tonic-gate NULL, 136*7c478bd9Sstevel@tonic-gate &logdmuxm_info 137*7c478bd9Sstevel@tonic-gate }; 138*7c478bd9Sstevel@tonic-gate 139*7c478bd9Sstevel@tonic-gate static struct qinit logdmuxlrinit = { 140*7c478bd9Sstevel@tonic-gate logdmuxlrput, 141*7c478bd9Sstevel@tonic-gate logdmuxlrsrv, 142*7c478bd9Sstevel@tonic-gate NULL, 143*7c478bd9Sstevel@tonic-gate NULL, 144*7c478bd9Sstevel@tonic-gate NULL, 145*7c478bd9Sstevel@tonic-gate &logdmuxm_info 146*7c478bd9Sstevel@tonic-gate }; 147*7c478bd9Sstevel@tonic-gate 148*7c478bd9Sstevel@tonic-gate static struct qinit logdmuxlwinit = { 149*7c478bd9Sstevel@tonic-gate NULL, 150*7c478bd9Sstevel@tonic-gate logdmuxlwsrv, 151*7c478bd9Sstevel@tonic-gate NULL, 152*7c478bd9Sstevel@tonic-gate NULL, 153*7c478bd9Sstevel@tonic-gate NULL, 154*7c478bd9Sstevel@tonic-gate &logdmuxm_info 155*7c478bd9Sstevel@tonic-gate }; 156*7c478bd9Sstevel@tonic-gate 157*7c478bd9Sstevel@tonic-gate struct streamtab logdmuxinfo = { 158*7c478bd9Sstevel@tonic-gate &logdmuxurinit, 159*7c478bd9Sstevel@tonic-gate &logdmuxuwinit, 160*7c478bd9Sstevel@tonic-gate &logdmuxlrinit, 161*7c478bd9Sstevel@tonic-gate &logdmuxlwinit 162*7c478bd9Sstevel@tonic-gate }; 163*7c478bd9Sstevel@tonic-gate 164*7c478bd9Sstevel@tonic-gate static int logdmux_info(dev_info_t *, ddi_info_cmd_t, void *, void **); 165*7c478bd9Sstevel@tonic-gate static int logdmux_attach(dev_info_t *, ddi_attach_cmd_t); 166*7c478bd9Sstevel@tonic-gate static int logdmux_detach(dev_info_t *, ddi_detach_cmd_t); 167*7c478bd9Sstevel@tonic-gate static dev_info_t *logdmux_dip; 168*7c478bd9Sstevel@tonic-gate 169*7c478bd9Sstevel@tonic-gate DDI_DEFINE_STREAM_OPS(logdmux_ops, nulldev, nulldev, logdmux_attach, 170*7c478bd9Sstevel@tonic-gate logdmux_detach, nulldev, logdmux_info, D_MP | D_MTPERQ, &logdmuxinfo); 171*7c478bd9Sstevel@tonic-gate 172*7c478bd9Sstevel@tonic-gate static struct modldrv modldrv = { 173*7c478bd9Sstevel@tonic-gate &mod_driverops, 174*7c478bd9Sstevel@tonic-gate "logindmux driver %I%", 175*7c478bd9Sstevel@tonic-gate &logdmux_ops 176*7c478bd9Sstevel@tonic-gate }; 177*7c478bd9Sstevel@tonic-gate 178*7c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 179*7c478bd9Sstevel@tonic-gate MODREV_1, &modldrv, NULL 180*7c478bd9Sstevel@tonic-gate }; 181*7c478bd9Sstevel@tonic-gate 182*7c478bd9Sstevel@tonic-gate int 183*7c478bd9Sstevel@tonic-gate _init(void) 184*7c478bd9Sstevel@tonic-gate { 185*7c478bd9Sstevel@tonic-gate int ret; 186*7c478bd9Sstevel@tonic-gate 187*7c478bd9Sstevel@tonic-gate mutex_init(&logdmux_peerq_lock, NULL, MUTEX_DRIVER, NULL); 188*7c478bd9Sstevel@tonic-gate mutex_init(&logdmux_qexch_lock, NULL, MUTEX_DRIVER, NULL); 189*7c478bd9Sstevel@tonic-gate 190*7c478bd9Sstevel@tonic-gate if ((ret = mod_install(&modlinkage)) != 0) { 191*7c478bd9Sstevel@tonic-gate mutex_destroy(&logdmux_peerq_lock); 192*7c478bd9Sstevel@tonic-gate mutex_destroy(&logdmux_qexch_lock); 193*7c478bd9Sstevel@tonic-gate return (ret); 194*7c478bd9Sstevel@tonic-gate } 195*7c478bd9Sstevel@tonic-gate 196*7c478bd9Sstevel@tonic-gate logdmux_minor_arena = vmem_create("logdmux_minor", (void *)1, 197*7c478bd9Sstevel@tonic-gate logdmux_maxminor, 1, NULL, NULL, NULL, 0, 198*7c478bd9Sstevel@tonic-gate VM_SLEEP | VMC_IDENTIFIER); 199*7c478bd9Sstevel@tonic-gate (void) ddi_soft_state_init(&logdmux_statep, sizeof (struct tmx), 1); 200*7c478bd9Sstevel@tonic-gate 201*7c478bd9Sstevel@tonic-gate return (0); 202*7c478bd9Sstevel@tonic-gate } 203*7c478bd9Sstevel@tonic-gate 204*7c478bd9Sstevel@tonic-gate int 205*7c478bd9Sstevel@tonic-gate _fini(void) 206*7c478bd9Sstevel@tonic-gate { 207*7c478bd9Sstevel@tonic-gate int ret; 208*7c478bd9Sstevel@tonic-gate 209*7c478bd9Sstevel@tonic-gate if ((ret = mod_remove(&modlinkage)) == 0) { 210*7c478bd9Sstevel@tonic-gate mutex_destroy(&logdmux_peerq_lock); 211*7c478bd9Sstevel@tonic-gate mutex_destroy(&logdmux_qexch_lock); 212*7c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&logdmux_statep); 213*7c478bd9Sstevel@tonic-gate vmem_destroy(logdmux_minor_arena); 214*7c478bd9Sstevel@tonic-gate logdmux_minor_arena = NULL; 215*7c478bd9Sstevel@tonic-gate } 216*7c478bd9Sstevel@tonic-gate 217*7c478bd9Sstevel@tonic-gate return (ret); 218*7c478bd9Sstevel@tonic-gate } 219*7c478bd9Sstevel@tonic-gate 220*7c478bd9Sstevel@tonic-gate int 221*7c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 222*7c478bd9Sstevel@tonic-gate { 223*7c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 224*7c478bd9Sstevel@tonic-gate } 225*7c478bd9Sstevel@tonic-gate 226*7c478bd9Sstevel@tonic-gate static int 227*7c478bd9Sstevel@tonic-gate logdmux_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 228*7c478bd9Sstevel@tonic-gate { 229*7c478bd9Sstevel@tonic-gate if (cmd != DDI_ATTACH) 230*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 231*7c478bd9Sstevel@tonic-gate 232*7c478bd9Sstevel@tonic-gate if (ddi_create_minor_node(devi, "logindmux", S_IFCHR, 0, DDI_PSEUDO, 233*7c478bd9Sstevel@tonic-gate CLONE_DEV) == DDI_FAILURE) 234*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 235*7c478bd9Sstevel@tonic-gate 236*7c478bd9Sstevel@tonic-gate logdmux_dip = devi; 237*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 238*7c478bd9Sstevel@tonic-gate } 239*7c478bd9Sstevel@tonic-gate 240*7c478bd9Sstevel@tonic-gate static int 241*7c478bd9Sstevel@tonic-gate logdmux_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) 242*7c478bd9Sstevel@tonic-gate { 243*7c478bd9Sstevel@tonic-gate if (cmd != DDI_DETACH) 244*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 245*7c478bd9Sstevel@tonic-gate 246*7c478bd9Sstevel@tonic-gate ddi_remove_minor_node(devi, NULL); 247*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 248*7c478bd9Sstevel@tonic-gate } 249*7c478bd9Sstevel@tonic-gate 250*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 251*7c478bd9Sstevel@tonic-gate static int 252*7c478bd9Sstevel@tonic-gate logdmux_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 253*7c478bd9Sstevel@tonic-gate { 254*7c478bd9Sstevel@tonic-gate int error; 255*7c478bd9Sstevel@tonic-gate 256*7c478bd9Sstevel@tonic-gate switch (infocmd) { 257*7c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 258*7c478bd9Sstevel@tonic-gate if (logdmux_dip == NULL) { 259*7c478bd9Sstevel@tonic-gate error = DDI_FAILURE; 260*7c478bd9Sstevel@tonic-gate } else { 261*7c478bd9Sstevel@tonic-gate *result = logdmux_dip; 262*7c478bd9Sstevel@tonic-gate error = DDI_SUCCESS; 263*7c478bd9Sstevel@tonic-gate } 264*7c478bd9Sstevel@tonic-gate break; 265*7c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 266*7c478bd9Sstevel@tonic-gate *result = (void *)0; 267*7c478bd9Sstevel@tonic-gate error = DDI_SUCCESS; 268*7c478bd9Sstevel@tonic-gate break; 269*7c478bd9Sstevel@tonic-gate default: 270*7c478bd9Sstevel@tonic-gate error = DDI_FAILURE; 271*7c478bd9Sstevel@tonic-gate } 272*7c478bd9Sstevel@tonic-gate return (error); 273*7c478bd9Sstevel@tonic-gate } 274*7c478bd9Sstevel@tonic-gate 275*7c478bd9Sstevel@tonic-gate /* 276*7c478bd9Sstevel@tonic-gate * Logindmux open routine 277*7c478bd9Sstevel@tonic-gate */ 278*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 279*7c478bd9Sstevel@tonic-gate static int 280*7c478bd9Sstevel@tonic-gate logdmuxopen(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *crp) 281*7c478bd9Sstevel@tonic-gate { 282*7c478bd9Sstevel@tonic-gate struct tmx *tmxp; 283*7c478bd9Sstevel@tonic-gate minor_t minor, omaxminor; 284*7c478bd9Sstevel@tonic-gate 285*7c478bd9Sstevel@tonic-gate if (sflag != CLONEOPEN) 286*7c478bd9Sstevel@tonic-gate return (EINVAL); 287*7c478bd9Sstevel@tonic-gate 288*7c478bd9Sstevel@tonic-gate mutex_enter(&logdmux_minor_lock); 289*7c478bd9Sstevel@tonic-gate if (vmem_size(logdmux_minor_arena, VMEM_FREE) == 0) { 290*7c478bd9Sstevel@tonic-gate /* 291*7c478bd9Sstevel@tonic-gate * The arena has been exhausted; grow by powers of two 292*7c478bd9Sstevel@tonic-gate * up to MAXMIN; bail if we've run out of minors. 293*7c478bd9Sstevel@tonic-gate */ 294*7c478bd9Sstevel@tonic-gate if (logdmux_maxminor == MAXMIN) { 295*7c478bd9Sstevel@tonic-gate mutex_exit(&logdmux_minor_lock); 296*7c478bd9Sstevel@tonic-gate return (ENOMEM); 297*7c478bd9Sstevel@tonic-gate } 298*7c478bd9Sstevel@tonic-gate 299*7c478bd9Sstevel@tonic-gate omaxminor = logdmux_maxminor; 300*7c478bd9Sstevel@tonic-gate logdmux_maxminor = MIN(logdmux_maxminor << 1, MAXMIN); 301*7c478bd9Sstevel@tonic-gate 302*7c478bd9Sstevel@tonic-gate (void) vmem_add(logdmux_minor_arena, 303*7c478bd9Sstevel@tonic-gate (void *)(uintptr_t)(omaxminor + 1), 304*7c478bd9Sstevel@tonic-gate logdmux_maxminor - omaxminor, VM_SLEEP); 305*7c478bd9Sstevel@tonic-gate } 306*7c478bd9Sstevel@tonic-gate minor = (minor_t)(uintptr_t) 307*7c478bd9Sstevel@tonic-gate vmem_alloc(logdmux_minor_arena, 1, VM_SLEEP); 308*7c478bd9Sstevel@tonic-gate mutex_exit(&logdmux_minor_lock); 309*7c478bd9Sstevel@tonic-gate 310*7c478bd9Sstevel@tonic-gate if (ddi_soft_state_zalloc(logdmux_statep, minor) == DDI_FAILURE) { 311*7c478bd9Sstevel@tonic-gate vmem_free(logdmux_minor_arena, (void *)(uintptr_t)minor, 1); 312*7c478bd9Sstevel@tonic-gate return (ENOMEM); 313*7c478bd9Sstevel@tonic-gate } 314*7c478bd9Sstevel@tonic-gate 315*7c478bd9Sstevel@tonic-gate tmxp = ddi_get_soft_state(logdmux_statep, minor); 316*7c478bd9Sstevel@tonic-gate tmxp->rdq = q; 317*7c478bd9Sstevel@tonic-gate tmxp->muxq = NULL; 318*7c478bd9Sstevel@tonic-gate tmxp->peerq = NULL; 319*7c478bd9Sstevel@tonic-gate tmxp->unlinkinfop = NULL; 320*7c478bd9Sstevel@tonic-gate tmxp->dev0 = minor; 321*7c478bd9Sstevel@tonic-gate 322*7c478bd9Sstevel@tonic-gate *devp = makedevice(getmajor(*devp), tmxp->dev0); 323*7c478bd9Sstevel@tonic-gate q->q_ptr = tmxp; 324*7c478bd9Sstevel@tonic-gate WR(q)->q_ptr = tmxp; 325*7c478bd9Sstevel@tonic-gate 326*7c478bd9Sstevel@tonic-gate qprocson(q); 327*7c478bd9Sstevel@tonic-gate return (0); 328*7c478bd9Sstevel@tonic-gate } 329*7c478bd9Sstevel@tonic-gate 330*7c478bd9Sstevel@tonic-gate /* 331*7c478bd9Sstevel@tonic-gate * Logindmux close routine gets called when telnet connection is closed 332*7c478bd9Sstevel@tonic-gate */ 333*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 334*7c478bd9Sstevel@tonic-gate static int 335*7c478bd9Sstevel@tonic-gate logdmuxclose(queue_t *q, int flag, cred_t *crp) 336*7c478bd9Sstevel@tonic-gate { 337*7c478bd9Sstevel@tonic-gate struct tmx *tmxp = q->q_ptr; 338*7c478bd9Sstevel@tonic-gate minor_t minor = tmxp->dev0; 339*7c478bd9Sstevel@tonic-gate 340*7c478bd9Sstevel@tonic-gate ASSERT(tmxp->muxq == NULL); 341*7c478bd9Sstevel@tonic-gate ASSERT(tmxp->peerq == NULL); 342*7c478bd9Sstevel@tonic-gate 343*7c478bd9Sstevel@tonic-gate qprocsoff(q); 344*7c478bd9Sstevel@tonic-gate if (tmxp->wbufcid != 0) { 345*7c478bd9Sstevel@tonic-gate qunbufcall(q, tmxp->wbufcid); 346*7c478bd9Sstevel@tonic-gate tmxp->wbufcid = 0; 347*7c478bd9Sstevel@tonic-gate } 348*7c478bd9Sstevel@tonic-gate if (tmxp->rbufcid != 0) { 349*7c478bd9Sstevel@tonic-gate qunbufcall(q, tmxp->rbufcid); 350*7c478bd9Sstevel@tonic-gate tmxp->rbufcid = 0; 351*7c478bd9Sstevel@tonic-gate } 352*7c478bd9Sstevel@tonic-gate if (tmxp->rtimoutid != 0) { 353*7c478bd9Sstevel@tonic-gate (void) quntimeout(q, tmxp->rtimoutid); 354*7c478bd9Sstevel@tonic-gate tmxp->rtimoutid = 0; 355*7c478bd9Sstevel@tonic-gate } 356*7c478bd9Sstevel@tonic-gate if (tmxp->wtimoutid != 0) { 357*7c478bd9Sstevel@tonic-gate (void) quntimeout(q, tmxp->wtimoutid); 358*7c478bd9Sstevel@tonic-gate tmxp->wtimoutid = 0; 359*7c478bd9Sstevel@tonic-gate } 360*7c478bd9Sstevel@tonic-gate if (tmxp->utimoutid != 0) { 361*7c478bd9Sstevel@tonic-gate (void) quntimeout(q, tmxp->utimoutid); 362*7c478bd9Sstevel@tonic-gate tmxp->utimoutid = 0; 363*7c478bd9Sstevel@tonic-gate } 364*7c478bd9Sstevel@tonic-gate 365*7c478bd9Sstevel@tonic-gate /* 366*7c478bd9Sstevel@tonic-gate * Hold logdmux_qexch_lock to prevent another thread that might be 367*7c478bd9Sstevel@tonic-gate * in LOGDMX_IOC_QEXCHANGE from looking up our state while we're 368*7c478bd9Sstevel@tonic-gate * disposing of it. 369*7c478bd9Sstevel@tonic-gate */ 370*7c478bd9Sstevel@tonic-gate mutex_enter(&logdmux_qexch_lock); 371*7c478bd9Sstevel@tonic-gate ddi_soft_state_free(logdmux_statep, minor); 372*7c478bd9Sstevel@tonic-gate vmem_free(logdmux_minor_arena, (void *)(uintptr_t)minor, 1); 373*7c478bd9Sstevel@tonic-gate mutex_exit(&logdmux_qexch_lock); 374*7c478bd9Sstevel@tonic-gate 375*7c478bd9Sstevel@tonic-gate q->q_ptr = NULL; 376*7c478bd9Sstevel@tonic-gate WR(q)->q_ptr = NULL; 377*7c478bd9Sstevel@tonic-gate 378*7c478bd9Sstevel@tonic-gate return (0); 379*7c478bd9Sstevel@tonic-gate } 380*7c478bd9Sstevel@tonic-gate 381*7c478bd9Sstevel@tonic-gate /* 382*7c478bd9Sstevel@tonic-gate * Upper read service routine 383*7c478bd9Sstevel@tonic-gate */ 384*7c478bd9Sstevel@tonic-gate static int 385*7c478bd9Sstevel@tonic-gate logdmuxursrv(queue_t *q) 386*7c478bd9Sstevel@tonic-gate { 387*7c478bd9Sstevel@tonic-gate struct tmx *tmxp = q->q_ptr; 388*7c478bd9Sstevel@tonic-gate 389*7c478bd9Sstevel@tonic-gate if (tmxp->muxq != NULL) 390*7c478bd9Sstevel@tonic-gate qenable(RD(tmxp->muxq)); 391*7c478bd9Sstevel@tonic-gate return (0); 392*7c478bd9Sstevel@tonic-gate } 393*7c478bd9Sstevel@tonic-gate 394*7c478bd9Sstevel@tonic-gate /* 395*7c478bd9Sstevel@tonic-gate * This routine gets called when telnet daemon sends data or ioctl messages 396*7c478bd9Sstevel@tonic-gate * to upper mux queue. 397*7c478bd9Sstevel@tonic-gate */ 398*7c478bd9Sstevel@tonic-gate static int 399*7c478bd9Sstevel@tonic-gate logdmuxuwput(queue_t *q, mblk_t *mp) 400*7c478bd9Sstevel@tonic-gate { 401*7c478bd9Sstevel@tonic-gate queue_t *qp; 402*7c478bd9Sstevel@tonic-gate mblk_t *newmp; 403*7c478bd9Sstevel@tonic-gate struct iocblk *ioc; 404*7c478bd9Sstevel@tonic-gate minor_t minor; 405*7c478bd9Sstevel@tonic-gate STRUCT_HANDLE(protocol_arg, protoh); 406*7c478bd9Sstevel@tonic-gate struct tmx *tmxp, *tmxpeerp; 407*7c478bd9Sstevel@tonic-gate int error; 408*7c478bd9Sstevel@tonic-gate 409*7c478bd9Sstevel@tonic-gate tmxp = q->q_ptr; 410*7c478bd9Sstevel@tonic-gate 411*7c478bd9Sstevel@tonic-gate switch (mp->b_datap->db_type) { 412*7c478bd9Sstevel@tonic-gate 413*7c478bd9Sstevel@tonic-gate case M_IOCTL: 414*7c478bd9Sstevel@tonic-gate ASSERT(MBLKL(mp) == sizeof (struct iocblk)); 415*7c478bd9Sstevel@tonic-gate 416*7c478bd9Sstevel@tonic-gate ioc = (struct iocblk *)mp->b_rptr; 417*7c478bd9Sstevel@tonic-gate switch (ioc->ioc_cmd) { 418*7c478bd9Sstevel@tonic-gate /* 419*7c478bd9Sstevel@tonic-gate * This is a special ioctl which exchanges q info 420*7c478bd9Sstevel@tonic-gate * of the two peers, connected to netf and ptmx. 421*7c478bd9Sstevel@tonic-gate */ 422*7c478bd9Sstevel@tonic-gate case LOGDMX_IOC_QEXCHANGE: 423*7c478bd9Sstevel@tonic-gate error = miocpullup(mp, 424*7c478bd9Sstevel@tonic-gate SIZEOF_STRUCT(protocol_arg, ioc->ioc_flag)); 425*7c478bd9Sstevel@tonic-gate if (error != 0) { 426*7c478bd9Sstevel@tonic-gate miocnak(q, mp, 0, error); 427*7c478bd9Sstevel@tonic-gate break; 428*7c478bd9Sstevel@tonic-gate } 429*7c478bd9Sstevel@tonic-gate STRUCT_SET_HANDLE(protoh, ioc->ioc_flag, 430*7c478bd9Sstevel@tonic-gate (struct protocol_arg *)mp->b_cont->b_rptr); 431*7c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 432*7c478bd9Sstevel@tonic-gate if ((ioc->ioc_flag & DATAMODEL_MASK) == 433*7c478bd9Sstevel@tonic-gate DATAMODEL_ILP32) { 434*7c478bd9Sstevel@tonic-gate minor = getminor(expldev( 435*7c478bd9Sstevel@tonic-gate STRUCT_FGET(protoh, dev))); 436*7c478bd9Sstevel@tonic-gate } else 437*7c478bd9Sstevel@tonic-gate #endif 438*7c478bd9Sstevel@tonic-gate { 439*7c478bd9Sstevel@tonic-gate minor = getminor(STRUCT_FGET(protoh, dev)); 440*7c478bd9Sstevel@tonic-gate } 441*7c478bd9Sstevel@tonic-gate 442*7c478bd9Sstevel@tonic-gate /* 443*7c478bd9Sstevel@tonic-gate * The second argument to ddi_get_soft_state() is 444*7c478bd9Sstevel@tonic-gate * interpreted as an `int', so prohibit negative 445*7c478bd9Sstevel@tonic-gate * values. 446*7c478bd9Sstevel@tonic-gate */ 447*7c478bd9Sstevel@tonic-gate if ((int)minor < 0) { 448*7c478bd9Sstevel@tonic-gate miocnak(q, mp, 0, EINVAL); 449*7c478bd9Sstevel@tonic-gate break; 450*7c478bd9Sstevel@tonic-gate } 451*7c478bd9Sstevel@tonic-gate 452*7c478bd9Sstevel@tonic-gate /* 453*7c478bd9Sstevel@tonic-gate * We must hold logdmux_qexch_lock while looking up 454*7c478bd9Sstevel@tonic-gate * the proposed peer to prevent another thread from 455*7c478bd9Sstevel@tonic-gate * simultaneously I_UNLINKing or closing it. 456*7c478bd9Sstevel@tonic-gate */ 457*7c478bd9Sstevel@tonic-gate mutex_enter(&logdmux_qexch_lock); 458*7c478bd9Sstevel@tonic-gate 459*7c478bd9Sstevel@tonic-gate /* 460*7c478bd9Sstevel@tonic-gate * For LOGDMX_IOC_QEXCHANGE to succeed, our peer must 461*7c478bd9Sstevel@tonic-gate * exist (and not be us), and both we and our peer 462*7c478bd9Sstevel@tonic-gate * must be I_LINKed (i.e., muxq must not be NULL) and 463*7c478bd9Sstevel@tonic-gate * not already have a peer. 464*7c478bd9Sstevel@tonic-gate */ 465*7c478bd9Sstevel@tonic-gate tmxpeerp = ddi_get_soft_state(logdmux_statep, minor); 466*7c478bd9Sstevel@tonic-gate if (tmxpeerp == NULL || tmxpeerp == tmxp || 467*7c478bd9Sstevel@tonic-gate tmxpeerp->muxq == NULL || tmxpeerp->peerq != NULL || 468*7c478bd9Sstevel@tonic-gate tmxp->muxq == NULL || tmxp->peerq != NULL) { 469*7c478bd9Sstevel@tonic-gate mutex_exit(&logdmux_qexch_lock); 470*7c478bd9Sstevel@tonic-gate miocnak(q, mp, 0, EINVAL); 471*7c478bd9Sstevel@tonic-gate break; 472*7c478bd9Sstevel@tonic-gate } 473*7c478bd9Sstevel@tonic-gate 474*7c478bd9Sstevel@tonic-gate /* 475*7c478bd9Sstevel@tonic-gate * If `flag' is set then exchange queues and assume 476*7c478bd9Sstevel@tonic-gate * tmxp refers to the ptmx stream. 477*7c478bd9Sstevel@tonic-gate */ 478*7c478bd9Sstevel@tonic-gate if (STRUCT_FGET(protoh, flag)) { 479*7c478bd9Sstevel@tonic-gate /* 480*7c478bd9Sstevel@tonic-gate * Allocate and populate the structure we 481*7c478bd9Sstevel@tonic-gate * need when processing an I_UNLINK ioctl. 482*7c478bd9Sstevel@tonic-gate * Give both logindmux instances a pointer 483*7c478bd9Sstevel@tonic-gate * to it from their tmx structure. 484*7c478bd9Sstevel@tonic-gate */ 485*7c478bd9Sstevel@tonic-gate if ((error = logdmux_alloc_unlinkinfo( 486*7c478bd9Sstevel@tonic-gate tmxp, tmxpeerp)) != 0) { 487*7c478bd9Sstevel@tonic-gate mutex_exit(&logdmux_qexch_lock); 488*7c478bd9Sstevel@tonic-gate miocnak(q, mp, 0, error); 489*7c478bd9Sstevel@tonic-gate break; 490*7c478bd9Sstevel@tonic-gate } 491*7c478bd9Sstevel@tonic-gate tmxp->peerq = tmxpeerp->muxq; 492*7c478bd9Sstevel@tonic-gate tmxpeerp->peerq = tmxp->muxq; 493*7c478bd9Sstevel@tonic-gate tmxp->isptm = B_TRUE; 494*7c478bd9Sstevel@tonic-gate } 495*7c478bd9Sstevel@tonic-gate mutex_exit(&logdmux_qexch_lock); 496*7c478bd9Sstevel@tonic-gate miocack(q, mp, 0, 0); 497*7c478bd9Sstevel@tonic-gate break; 498*7c478bd9Sstevel@tonic-gate 499*7c478bd9Sstevel@tonic-gate case I_LINK: 500*7c478bd9Sstevel@tonic-gate ASSERT(MBLKL(mp->b_cont) == sizeof (struct linkblk)); 501*7c478bd9Sstevel@tonic-gate logdmuxlink(q, mp); 502*7c478bd9Sstevel@tonic-gate break; 503*7c478bd9Sstevel@tonic-gate 504*7c478bd9Sstevel@tonic-gate case I_UNLINK: 505*7c478bd9Sstevel@tonic-gate ASSERT(MBLKL(mp->b_cont) == sizeof (struct linkblk)); 506*7c478bd9Sstevel@tonic-gate logdmuxunlink(q, mp); 507*7c478bd9Sstevel@tonic-gate break; 508*7c478bd9Sstevel@tonic-gate 509*7c478bd9Sstevel@tonic-gate default: 510*7c478bd9Sstevel@tonic-gate if (tmxp->muxq == NULL) { 511*7c478bd9Sstevel@tonic-gate miocnak(q, mp, 0, EINVAL); 512*7c478bd9Sstevel@tonic-gate return (0); 513*7c478bd9Sstevel@tonic-gate } 514*7c478bd9Sstevel@tonic-gate putnext(tmxp->muxq, mp); 515*7c478bd9Sstevel@tonic-gate break; 516*7c478bd9Sstevel@tonic-gate } 517*7c478bd9Sstevel@tonic-gate 518*7c478bd9Sstevel@tonic-gate break; 519*7c478bd9Sstevel@tonic-gate 520*7c478bd9Sstevel@tonic-gate case M_DATA: 521*7c478bd9Sstevel@tonic-gate if (!tmxp->isptm) { 522*7c478bd9Sstevel@tonic-gate if ((newmp = allocb(sizeof (char), BPRI_MED)) == NULL) { 523*7c478bd9Sstevel@tonic-gate recover(q, mp, sizeof (char)); 524*7c478bd9Sstevel@tonic-gate return (0); 525*7c478bd9Sstevel@tonic-gate } 526*7c478bd9Sstevel@tonic-gate newmp->b_datap->db_type = M_CTL; 527*7c478bd9Sstevel@tonic-gate *newmp->b_wptr++ = M_CTL_MAGIC_NUMBER; 528*7c478bd9Sstevel@tonic-gate newmp->b_cont = mp; 529*7c478bd9Sstevel@tonic-gate mp = newmp; 530*7c478bd9Sstevel@tonic-gate } 531*7c478bd9Sstevel@tonic-gate /* FALLTHRU */ 532*7c478bd9Sstevel@tonic-gate 533*7c478bd9Sstevel@tonic-gate case M_PROTO: 534*7c478bd9Sstevel@tonic-gate case M_PCPROTO: 535*7c478bd9Sstevel@tonic-gate qp = tmxp->muxq; 536*7c478bd9Sstevel@tonic-gate if (qp == NULL) { 537*7c478bd9Sstevel@tonic-gate merror(q, mp, EINVAL); 538*7c478bd9Sstevel@tonic-gate return (0); 539*7c478bd9Sstevel@tonic-gate } 540*7c478bd9Sstevel@tonic-gate 541*7c478bd9Sstevel@tonic-gate if (queclass(mp) < QPCTL) { 542*7c478bd9Sstevel@tonic-gate if (q->q_first != NULL || !canputnext(qp)) { 543*7c478bd9Sstevel@tonic-gate (void) putq(q, mp); 544*7c478bd9Sstevel@tonic-gate return (0); 545*7c478bd9Sstevel@tonic-gate } 546*7c478bd9Sstevel@tonic-gate } 547*7c478bd9Sstevel@tonic-gate putnext(qp, mp); 548*7c478bd9Sstevel@tonic-gate break; 549*7c478bd9Sstevel@tonic-gate 550*7c478bd9Sstevel@tonic-gate case M_FLUSH: 551*7c478bd9Sstevel@tonic-gate if (*mp->b_rptr & FLUSHW) 552*7c478bd9Sstevel@tonic-gate flushq(q, FLUSHALL); 553*7c478bd9Sstevel@tonic-gate 554*7c478bd9Sstevel@tonic-gate if (tmxp->muxq != NULL) { 555*7c478bd9Sstevel@tonic-gate putnext(tmxp->muxq, mp); 556*7c478bd9Sstevel@tonic-gate return (0); 557*7c478bd9Sstevel@tonic-gate } 558*7c478bd9Sstevel@tonic-gate 559*7c478bd9Sstevel@tonic-gate *mp->b_rptr &= ~FLUSHW; 560*7c478bd9Sstevel@tonic-gate if (*mp->b_rptr & FLUSHR) 561*7c478bd9Sstevel@tonic-gate qreply(q, mp); 562*7c478bd9Sstevel@tonic-gate else 563*7c478bd9Sstevel@tonic-gate freemsg(mp); 564*7c478bd9Sstevel@tonic-gate break; 565*7c478bd9Sstevel@tonic-gate 566*7c478bd9Sstevel@tonic-gate default: 567*7c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "logdmuxuwput: received unexpected message" 568*7c478bd9Sstevel@tonic-gate " of type 0x%x", mp->b_datap->db_type); 569*7c478bd9Sstevel@tonic-gate freemsg(mp); 570*7c478bd9Sstevel@tonic-gate } 571*7c478bd9Sstevel@tonic-gate return (0); 572*7c478bd9Sstevel@tonic-gate } 573*7c478bd9Sstevel@tonic-gate 574*7c478bd9Sstevel@tonic-gate /* 575*7c478bd9Sstevel@tonic-gate * Upper write service routine 576*7c478bd9Sstevel@tonic-gate */ 577*7c478bd9Sstevel@tonic-gate static int 578*7c478bd9Sstevel@tonic-gate logdmuxuwsrv(queue_t *q) 579*7c478bd9Sstevel@tonic-gate { 580*7c478bd9Sstevel@tonic-gate mblk_t *mp, *newmp; 581*7c478bd9Sstevel@tonic-gate queue_t *qp; 582*7c478bd9Sstevel@tonic-gate struct tmx *tmxp = q->q_ptr; 583*7c478bd9Sstevel@tonic-gate 584*7c478bd9Sstevel@tonic-gate while ((mp = getq(q)) != NULL) { 585*7c478bd9Sstevel@tonic-gate switch (mp->b_datap->db_type) { 586*7c478bd9Sstevel@tonic-gate case M_DATA: 587*7c478bd9Sstevel@tonic-gate if (!tmxp->isptm) { 588*7c478bd9Sstevel@tonic-gate if ((newmp = allocb(sizeof (char), BPRI_MED)) == 589*7c478bd9Sstevel@tonic-gate NULL) { 590*7c478bd9Sstevel@tonic-gate recover(q, mp, sizeof (char)); 591*7c478bd9Sstevel@tonic-gate return (0); 592*7c478bd9Sstevel@tonic-gate } 593*7c478bd9Sstevel@tonic-gate newmp->b_datap->db_type = M_CTL; 594*7c478bd9Sstevel@tonic-gate *newmp->b_wptr++ = M_CTL_MAGIC_NUMBER; 595*7c478bd9Sstevel@tonic-gate newmp->b_cont = mp; 596*7c478bd9Sstevel@tonic-gate mp = newmp; 597*7c478bd9Sstevel@tonic-gate } 598*7c478bd9Sstevel@tonic-gate /* FALLTHRU */ 599*7c478bd9Sstevel@tonic-gate 600*7c478bd9Sstevel@tonic-gate case M_CTL: 601*7c478bd9Sstevel@tonic-gate case M_PROTO: 602*7c478bd9Sstevel@tonic-gate if (tmxp->muxq == NULL) { 603*7c478bd9Sstevel@tonic-gate merror(q, mp, EIO); 604*7c478bd9Sstevel@tonic-gate break; 605*7c478bd9Sstevel@tonic-gate } 606*7c478bd9Sstevel@tonic-gate qp = tmxp->muxq; 607*7c478bd9Sstevel@tonic-gate if (!canputnext(qp)) { 608*7c478bd9Sstevel@tonic-gate (void) putbq(q, mp); 609*7c478bd9Sstevel@tonic-gate return (0); 610*7c478bd9Sstevel@tonic-gate } 611*7c478bd9Sstevel@tonic-gate putnext(qp, mp); 612*7c478bd9Sstevel@tonic-gate break; 613*7c478bd9Sstevel@tonic-gate 614*7c478bd9Sstevel@tonic-gate 615*7c478bd9Sstevel@tonic-gate default: 616*7c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "logdmuxuwsrv: received unexpected" 617*7c478bd9Sstevel@tonic-gate " message of type 0x%x", mp->b_datap->db_type); 618*7c478bd9Sstevel@tonic-gate freemsg(mp); 619*7c478bd9Sstevel@tonic-gate } 620*7c478bd9Sstevel@tonic-gate } 621*7c478bd9Sstevel@tonic-gate return (0); 622*7c478bd9Sstevel@tonic-gate } 623*7c478bd9Sstevel@tonic-gate 624*7c478bd9Sstevel@tonic-gate /* 625*7c478bd9Sstevel@tonic-gate * Logindmux lower put routine detects from which of the two lower queues 626*7c478bd9Sstevel@tonic-gate * the data needs to be read from and writes it out to its peer queue. 627*7c478bd9Sstevel@tonic-gate * For protocol, it detects M_CTL and sends its data to the daemon. Also, 628*7c478bd9Sstevel@tonic-gate * for ioctl and other types of messages, it lets the daemon handle it. 629*7c478bd9Sstevel@tonic-gate */ 630*7c478bd9Sstevel@tonic-gate static int 631*7c478bd9Sstevel@tonic-gate logdmuxlrput(queue_t *q, mblk_t *mp) 632*7c478bd9Sstevel@tonic-gate { 633*7c478bd9Sstevel@tonic-gate mblk_t *savemp; 634*7c478bd9Sstevel@tonic-gate queue_t *qp; 635*7c478bd9Sstevel@tonic-gate struct iocblk *ioc; 636*7c478bd9Sstevel@tonic-gate struct tmx *tmxp = q->q_ptr; 637*7c478bd9Sstevel@tonic-gate uchar_t flush; 638*7c478bd9Sstevel@tonic-gate uint_t *messagep; 639*7c478bd9Sstevel@tonic-gate unlinkinfo_t *unlinkinfop = tmxp->unlinkinfop; 640*7c478bd9Sstevel@tonic-gate 641*7c478bd9Sstevel@tonic-gate if (tmxp->muxq == NULL || tmxp->peerq == NULL) { 642*7c478bd9Sstevel@tonic-gate freemsg(mp); 643*7c478bd9Sstevel@tonic-gate return (0); 644*7c478bd9Sstevel@tonic-gate } 645*7c478bd9Sstevel@tonic-gate 646*7c478bd9Sstevel@tonic-gate /* 647*7c478bd9Sstevel@tonic-gate * If there's already a message on our queue and the incoming 648*7c478bd9Sstevel@tonic-gate * message is not of a high-priority, enqueue the message -- 649*7c478bd9Sstevel@tonic-gate * but not if it's a logindmux protocol message. 650*7c478bd9Sstevel@tonic-gate */ 651*7c478bd9Sstevel@tonic-gate if ((q->q_first != NULL) && (queclass(mp) < QPCTL) && 652*7c478bd9Sstevel@tonic-gate (!LOGDMUX_PROTO_MBLK(mp))) { 653*7c478bd9Sstevel@tonic-gate (void) putq(q, mp); 654*7c478bd9Sstevel@tonic-gate return (0); 655*7c478bd9Sstevel@tonic-gate } 656*7c478bd9Sstevel@tonic-gate 657*7c478bd9Sstevel@tonic-gate switch (mp->b_datap->db_type) { 658*7c478bd9Sstevel@tonic-gate 659*7c478bd9Sstevel@tonic-gate case M_IOCTL: 660*7c478bd9Sstevel@tonic-gate ioc = (struct iocblk *)mp->b_rptr; 661*7c478bd9Sstevel@tonic-gate switch (ioc->ioc_cmd) { 662*7c478bd9Sstevel@tonic-gate 663*7c478bd9Sstevel@tonic-gate case TIOCSWINSZ: 664*7c478bd9Sstevel@tonic-gate case TCSETAF: 665*7c478bd9Sstevel@tonic-gate case TCSETSF: 666*7c478bd9Sstevel@tonic-gate case TCSETA: 667*7c478bd9Sstevel@tonic-gate case TCSETAW: 668*7c478bd9Sstevel@tonic-gate case TCSETS: 669*7c478bd9Sstevel@tonic-gate case TCSETSW: 670*7c478bd9Sstevel@tonic-gate case TCSBRK: 671*7c478bd9Sstevel@tonic-gate case TIOCSTI: 672*7c478bd9Sstevel@tonic-gate qp = tmxp->peerq; 673*7c478bd9Sstevel@tonic-gate break; 674*7c478bd9Sstevel@tonic-gate 675*7c478bd9Sstevel@tonic-gate default: 676*7c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "logdmuxlrput: received unexpected" 677*7c478bd9Sstevel@tonic-gate " request for ioctl 0x%x", ioc->ioc_cmd); 678*7c478bd9Sstevel@tonic-gate 679*7c478bd9Sstevel@tonic-gate /* NAK unrecognized ioctl's. */ 680*7c478bd9Sstevel@tonic-gate miocnak(q, mp, 0, 0); 681*7c478bd9Sstevel@tonic-gate return (0); 682*7c478bd9Sstevel@tonic-gate } 683*7c478bd9Sstevel@tonic-gate break; 684*7c478bd9Sstevel@tonic-gate 685*7c478bd9Sstevel@tonic-gate case M_DATA: 686*7c478bd9Sstevel@tonic-gate case M_HANGUP: 687*7c478bd9Sstevel@tonic-gate qp = tmxp->peerq; 688*7c478bd9Sstevel@tonic-gate break; 689*7c478bd9Sstevel@tonic-gate 690*7c478bd9Sstevel@tonic-gate case M_CTL: 691*7c478bd9Sstevel@tonic-gate /* 692*7c478bd9Sstevel@tonic-gate * The protocol messages that flow between the peers 693*7c478bd9Sstevel@tonic-gate * to implement the unlink functionality are M_CTLs 694*7c478bd9Sstevel@tonic-gate * which have the M_IOCTL/I_UNLINK mblk of the ioctl 695*7c478bd9Sstevel@tonic-gate * attached via b_cont. LOGDMUX_PROTO_MBLK() uses 696*7c478bd9Sstevel@tonic-gate * this to determine whether a particular M_CTL is a 697*7c478bd9Sstevel@tonic-gate * peer protocol message. 698*7c478bd9Sstevel@tonic-gate */ 699*7c478bd9Sstevel@tonic-gate if (LOGDMUX_PROTO_MBLK(mp)) { 700*7c478bd9Sstevel@tonic-gate messagep = (uint_t *)mp->b_rptr; 701*7c478bd9Sstevel@tonic-gate 702*7c478bd9Sstevel@tonic-gate switch (*messagep) { 703*7c478bd9Sstevel@tonic-gate 704*7c478bd9Sstevel@tonic-gate case LOGDMUX_UNLINK_REQ: 705*7c478bd9Sstevel@tonic-gate /* 706*7c478bd9Sstevel@tonic-gate * We've received a message from our 707*7c478bd9Sstevel@tonic-gate * peer indicating that it wants to 708*7c478bd9Sstevel@tonic-gate * unlink. 709*7c478bd9Sstevel@tonic-gate */ 710*7c478bd9Sstevel@tonic-gate *messagep = LOGDMUX_UNLINK_RESP; 711*7c478bd9Sstevel@tonic-gate qp = tmxp->peerq; 712*7c478bd9Sstevel@tonic-gate 713*7c478bd9Sstevel@tonic-gate mutex_enter(&logdmux_peerq_lock); 714*7c478bd9Sstevel@tonic-gate tmxp->peerq = NULL; 715*7c478bd9Sstevel@tonic-gate mutex_exit(&logdmux_peerq_lock); 716*7c478bd9Sstevel@tonic-gate 717*7c478bd9Sstevel@tonic-gate put(RD(qp), mp); 718*7c478bd9Sstevel@tonic-gate return (0); 719*7c478bd9Sstevel@tonic-gate 720*7c478bd9Sstevel@tonic-gate case LOGDMUX_UNLINK_RESP: 721*7c478bd9Sstevel@tonic-gate /* 722*7c478bd9Sstevel@tonic-gate * We've received a positive response 723*7c478bd9Sstevel@tonic-gate * from our peer to an earlier 724*7c478bd9Sstevel@tonic-gate * LOGDMUX_UNLINK_REQ that we sent. 725*7c478bd9Sstevel@tonic-gate * We can now carry on with the unlink. 726*7c478bd9Sstevel@tonic-gate */ 727*7c478bd9Sstevel@tonic-gate qp = tmxp->rdq; 728*7c478bd9Sstevel@tonic-gate mutex_enter(&unlinkinfop->state_lock); 729*7c478bd9Sstevel@tonic-gate ASSERT(unlinkinfop->state == 730*7c478bd9Sstevel@tonic-gate LOGDMUX_UNLINK_PENDING); 731*7c478bd9Sstevel@tonic-gate unlinkinfop->state = LOGDMUX_UNLINKED; 732*7c478bd9Sstevel@tonic-gate mutex_exit(&unlinkinfop->state_lock); 733*7c478bd9Sstevel@tonic-gate logdmux_finish_unlink(WR(qp), mp->b_cont); 734*7c478bd9Sstevel@tonic-gate return (0); 735*7c478bd9Sstevel@tonic-gate } 736*7c478bd9Sstevel@tonic-gate } 737*7c478bd9Sstevel@tonic-gate 738*7c478bd9Sstevel@tonic-gate qp = tmxp->rdq; 739*7c478bd9Sstevel@tonic-gate if (q->q_first != NULL || !canputnext(qp)) { 740*7c478bd9Sstevel@tonic-gate (void) putq(q, mp); 741*7c478bd9Sstevel@tonic-gate return (0); 742*7c478bd9Sstevel@tonic-gate } 743*7c478bd9Sstevel@tonic-gate if ((MBLKL(mp) == 1) && (*mp->b_rptr == M_CTL_MAGIC_NUMBER)) { 744*7c478bd9Sstevel@tonic-gate savemp = mp->b_cont; 745*7c478bd9Sstevel@tonic-gate freeb(mp); 746*7c478bd9Sstevel@tonic-gate mp = savemp; 747*7c478bd9Sstevel@tonic-gate } 748*7c478bd9Sstevel@tonic-gate putnext(qp, mp); 749*7c478bd9Sstevel@tonic-gate return (0); 750*7c478bd9Sstevel@tonic-gate 751*7c478bd9Sstevel@tonic-gate case M_IOCACK: 752*7c478bd9Sstevel@tonic-gate case M_IOCNAK: 753*7c478bd9Sstevel@tonic-gate case M_PROTO: 754*7c478bd9Sstevel@tonic-gate case M_PCPROTO: 755*7c478bd9Sstevel@tonic-gate case M_PCSIG: 756*7c478bd9Sstevel@tonic-gate case M_SETOPTS: 757*7c478bd9Sstevel@tonic-gate qp = tmxp->rdq; 758*7c478bd9Sstevel@tonic-gate break; 759*7c478bd9Sstevel@tonic-gate 760*7c478bd9Sstevel@tonic-gate case M_ERROR: 761*7c478bd9Sstevel@tonic-gate if (tmxp->isptm) { 762*7c478bd9Sstevel@tonic-gate /* 763*7c478bd9Sstevel@tonic-gate * This error is from ptm. We could tell TCP to 764*7c478bd9Sstevel@tonic-gate * shutdown the connection, but it's easier to just 765*7c478bd9Sstevel@tonic-gate * wait for the daemon to get SIGCHLD and close from 766*7c478bd9Sstevel@tonic-gate * above. 767*7c478bd9Sstevel@tonic-gate */ 768*7c478bd9Sstevel@tonic-gate freemsg(mp); 769*7c478bd9Sstevel@tonic-gate return (0); 770*7c478bd9Sstevel@tonic-gate } 771*7c478bd9Sstevel@tonic-gate /* 772*7c478bd9Sstevel@tonic-gate * This is from TCP. Don't really know why we'd 773*7c478bd9Sstevel@tonic-gate * get this, but we have a pretty good idea what 774*7c478bd9Sstevel@tonic-gate * to do: Send M_HANGUP to the pty. 775*7c478bd9Sstevel@tonic-gate */ 776*7c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_HANGUP; 777*7c478bd9Sstevel@tonic-gate mp->b_wptr = mp->b_rptr; 778*7c478bd9Sstevel@tonic-gate qp = tmxp->peerq; 779*7c478bd9Sstevel@tonic-gate break; 780*7c478bd9Sstevel@tonic-gate 781*7c478bd9Sstevel@tonic-gate case M_FLUSH: 782*7c478bd9Sstevel@tonic-gate if (*mp->b_rptr & FLUSHR) 783*7c478bd9Sstevel@tonic-gate flushq_dataonly(q); 784*7c478bd9Sstevel@tonic-gate 785*7c478bd9Sstevel@tonic-gate if (mp->b_flag & MSGMARK) { 786*7c478bd9Sstevel@tonic-gate /* 787*7c478bd9Sstevel@tonic-gate * This M_FLUSH has been marked by the module 788*7c478bd9Sstevel@tonic-gate * below as intended for the upper queue, 789*7c478bd9Sstevel@tonic-gate * not the peer queue. 790*7c478bd9Sstevel@tonic-gate */ 791*7c478bd9Sstevel@tonic-gate qp = tmxp->rdq; 792*7c478bd9Sstevel@tonic-gate mp->b_flag &= ~MSGMARK; 793*7c478bd9Sstevel@tonic-gate } else { 794*7c478bd9Sstevel@tonic-gate /* 795*7c478bd9Sstevel@tonic-gate * Wrap this M_FLUSH through the mux. 796*7c478bd9Sstevel@tonic-gate * The FLUSHR and FLUSHW bits must be 797*7c478bd9Sstevel@tonic-gate * reversed. 798*7c478bd9Sstevel@tonic-gate */ 799*7c478bd9Sstevel@tonic-gate qp = tmxp->peerq; 800*7c478bd9Sstevel@tonic-gate flush = *mp->b_rptr; 801*7c478bd9Sstevel@tonic-gate *mp->b_rptr &= ~(FLUSHR | FLUSHW); 802*7c478bd9Sstevel@tonic-gate if (flush & FLUSHW) 803*7c478bd9Sstevel@tonic-gate *mp->b_rptr |= FLUSHR; 804*7c478bd9Sstevel@tonic-gate if (flush & FLUSHR) 805*7c478bd9Sstevel@tonic-gate *mp->b_rptr |= FLUSHW; 806*7c478bd9Sstevel@tonic-gate } 807*7c478bd9Sstevel@tonic-gate break; 808*7c478bd9Sstevel@tonic-gate 809*7c478bd9Sstevel@tonic-gate case M_START: 810*7c478bd9Sstevel@tonic-gate case M_STOP: 811*7c478bd9Sstevel@tonic-gate case M_STARTI: 812*7c478bd9Sstevel@tonic-gate case M_STOPI: 813*7c478bd9Sstevel@tonic-gate freemsg(mp); 814*7c478bd9Sstevel@tonic-gate return (0); 815*7c478bd9Sstevel@tonic-gate 816*7c478bd9Sstevel@tonic-gate default: 817*7c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "logdmuxlrput: received unexpected " 818*7c478bd9Sstevel@tonic-gate "message of type 0x%x", mp->b_datap->db_type); 819*7c478bd9Sstevel@tonic-gate freemsg(mp); 820*7c478bd9Sstevel@tonic-gate return (0); 821*7c478bd9Sstevel@tonic-gate } 822*7c478bd9Sstevel@tonic-gate if (queclass(mp) < QPCTL) { 823*7c478bd9Sstevel@tonic-gate if (q->q_first != NULL || !canputnext(qp)) { 824*7c478bd9Sstevel@tonic-gate (void) putq(q, mp); 825*7c478bd9Sstevel@tonic-gate return (0); 826*7c478bd9Sstevel@tonic-gate } 827*7c478bd9Sstevel@tonic-gate } 828*7c478bd9Sstevel@tonic-gate putnext(qp, mp); 829*7c478bd9Sstevel@tonic-gate return (0); 830*7c478bd9Sstevel@tonic-gate } 831*7c478bd9Sstevel@tonic-gate 832*7c478bd9Sstevel@tonic-gate /* 833*7c478bd9Sstevel@tonic-gate * Lower read service routine 834*7c478bd9Sstevel@tonic-gate */ 835*7c478bd9Sstevel@tonic-gate static int 836*7c478bd9Sstevel@tonic-gate logdmuxlrsrv(queue_t *q) 837*7c478bd9Sstevel@tonic-gate { 838*7c478bd9Sstevel@tonic-gate mblk_t *mp, *savemp; 839*7c478bd9Sstevel@tonic-gate queue_t *qp; 840*7c478bd9Sstevel@tonic-gate struct iocblk *ioc; 841*7c478bd9Sstevel@tonic-gate struct tmx *tmxp = q->q_ptr; 842*7c478bd9Sstevel@tonic-gate 843*7c478bd9Sstevel@tonic-gate while ((mp = getq(q)) != NULL) { 844*7c478bd9Sstevel@tonic-gate if (tmxp->muxq == NULL || tmxp->peerq == NULL) { 845*7c478bd9Sstevel@tonic-gate freemsg(mp); 846*7c478bd9Sstevel@tonic-gate continue; 847*7c478bd9Sstevel@tonic-gate } 848*7c478bd9Sstevel@tonic-gate 849*7c478bd9Sstevel@tonic-gate switch (mp->b_datap->db_type) { 850*7c478bd9Sstevel@tonic-gate 851*7c478bd9Sstevel@tonic-gate case M_IOCTL: 852*7c478bd9Sstevel@tonic-gate ioc = (struct iocblk *)mp->b_rptr; 853*7c478bd9Sstevel@tonic-gate 854*7c478bd9Sstevel@tonic-gate switch (ioc->ioc_cmd) { 855*7c478bd9Sstevel@tonic-gate 856*7c478bd9Sstevel@tonic-gate case TIOCSWINSZ: 857*7c478bd9Sstevel@tonic-gate case TCSETAF: 858*7c478bd9Sstevel@tonic-gate case TCSETSF: 859*7c478bd9Sstevel@tonic-gate case TCSETA: 860*7c478bd9Sstevel@tonic-gate case TCSETAW: 861*7c478bd9Sstevel@tonic-gate case TCSETS: 862*7c478bd9Sstevel@tonic-gate case TCSETSW: 863*7c478bd9Sstevel@tonic-gate case TCSBRK: 864*7c478bd9Sstevel@tonic-gate case TIOCSTI: 865*7c478bd9Sstevel@tonic-gate qp = tmxp->peerq; 866*7c478bd9Sstevel@tonic-gate break; 867*7c478bd9Sstevel@tonic-gate 868*7c478bd9Sstevel@tonic-gate default: 869*7c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "logdmuxlrsrv: received " 870*7c478bd9Sstevel@tonic-gate "unexpected request for ioctl 0x%x", 871*7c478bd9Sstevel@tonic-gate ioc->ioc_cmd); 872*7c478bd9Sstevel@tonic-gate 873*7c478bd9Sstevel@tonic-gate /* NAK unrecognized ioctl's. */ 874*7c478bd9Sstevel@tonic-gate miocnak(q, mp, 0, 0); 875*7c478bd9Sstevel@tonic-gate continue; 876*7c478bd9Sstevel@tonic-gate } 877*7c478bd9Sstevel@tonic-gate break; 878*7c478bd9Sstevel@tonic-gate 879*7c478bd9Sstevel@tonic-gate case M_DATA: 880*7c478bd9Sstevel@tonic-gate case M_HANGUP: 881*7c478bd9Sstevel@tonic-gate qp = tmxp->peerq; 882*7c478bd9Sstevel@tonic-gate break; 883*7c478bd9Sstevel@tonic-gate 884*7c478bd9Sstevel@tonic-gate case M_CTL: 885*7c478bd9Sstevel@tonic-gate qp = tmxp->rdq; 886*7c478bd9Sstevel@tonic-gate if (!canputnext(qp)) { 887*7c478bd9Sstevel@tonic-gate (void) putbq(q, mp); 888*7c478bd9Sstevel@tonic-gate return (0); 889*7c478bd9Sstevel@tonic-gate } 890*7c478bd9Sstevel@tonic-gate if (MBLKL(mp) == 1 && 891*7c478bd9Sstevel@tonic-gate (*mp->b_rptr == M_CTL_MAGIC_NUMBER)) { 892*7c478bd9Sstevel@tonic-gate savemp = mp->b_cont; 893*7c478bd9Sstevel@tonic-gate freeb(mp); 894*7c478bd9Sstevel@tonic-gate mp = savemp; 895*7c478bd9Sstevel@tonic-gate } 896*7c478bd9Sstevel@tonic-gate putnext(qp, mp); 897*7c478bd9Sstevel@tonic-gate continue; 898*7c478bd9Sstevel@tonic-gate 899*7c478bd9Sstevel@tonic-gate case M_PROTO: 900*7c478bd9Sstevel@tonic-gate case M_SETOPTS: 901*7c478bd9Sstevel@tonic-gate qp = tmxp->rdq; 902*7c478bd9Sstevel@tonic-gate break; 903*7c478bd9Sstevel@tonic-gate 904*7c478bd9Sstevel@tonic-gate default: 905*7c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "logdmuxlrsrv: received unexpected " 906*7c478bd9Sstevel@tonic-gate "message of type 0x%x", mp->b_datap->db_type); 907*7c478bd9Sstevel@tonic-gate freemsg(mp); 908*7c478bd9Sstevel@tonic-gate continue; 909*7c478bd9Sstevel@tonic-gate } 910*7c478bd9Sstevel@tonic-gate ASSERT(queclass(mp) < QPCTL); 911*7c478bd9Sstevel@tonic-gate if (!canputnext(qp)) { 912*7c478bd9Sstevel@tonic-gate (void) putbq(q, mp); 913*7c478bd9Sstevel@tonic-gate return (0); 914*7c478bd9Sstevel@tonic-gate } 915*7c478bd9Sstevel@tonic-gate putnext(qp, mp); 916*7c478bd9Sstevel@tonic-gate } 917*7c478bd9Sstevel@tonic-gate return (0); 918*7c478bd9Sstevel@tonic-gate } 919*7c478bd9Sstevel@tonic-gate 920*7c478bd9Sstevel@tonic-gate /* 921*7c478bd9Sstevel@tonic-gate * Lower side write service procedure. No messages are ever placed on 922*7c478bd9Sstevel@tonic-gate * the write queue here, this just back-enables all of the upper side 923*7c478bd9Sstevel@tonic-gate * write service procedures. 924*7c478bd9Sstevel@tonic-gate */ 925*7c478bd9Sstevel@tonic-gate static int 926*7c478bd9Sstevel@tonic-gate logdmuxlwsrv(queue_t *q) 927*7c478bd9Sstevel@tonic-gate { 928*7c478bd9Sstevel@tonic-gate struct tmx *tmxp = q->q_ptr; 929*7c478bd9Sstevel@tonic-gate 930*7c478bd9Sstevel@tonic-gate /* 931*7c478bd9Sstevel@tonic-gate * Qenable upper write queue and find out which lower 932*7c478bd9Sstevel@tonic-gate * queue needs to be restarted with flow control. 933*7c478bd9Sstevel@tonic-gate * Qenable the peer queue so canputnext will 934*7c478bd9Sstevel@tonic-gate * succeed on next call to logdmuxlrput. 935*7c478bd9Sstevel@tonic-gate */ 936*7c478bd9Sstevel@tonic-gate qenable(WR(tmxp->rdq)); 937*7c478bd9Sstevel@tonic-gate 938*7c478bd9Sstevel@tonic-gate mutex_enter(&logdmux_peerq_lock); 939*7c478bd9Sstevel@tonic-gate if (tmxp->peerq != NULL) 940*7c478bd9Sstevel@tonic-gate qenable(RD(tmxp->peerq)); 941*7c478bd9Sstevel@tonic-gate mutex_exit(&logdmux_peerq_lock); 942*7c478bd9Sstevel@tonic-gate 943*7c478bd9Sstevel@tonic-gate return (0); 944*7c478bd9Sstevel@tonic-gate } 945*7c478bd9Sstevel@tonic-gate 946*7c478bd9Sstevel@tonic-gate /* 947*7c478bd9Sstevel@tonic-gate * This routine does I_LINK operation. 948*7c478bd9Sstevel@tonic-gate */ 949*7c478bd9Sstevel@tonic-gate static void 950*7c478bd9Sstevel@tonic-gate logdmuxlink(queue_t *q, mblk_t *mp) 951*7c478bd9Sstevel@tonic-gate { 952*7c478bd9Sstevel@tonic-gate struct tmx *tmxp = q->q_ptr; 953*7c478bd9Sstevel@tonic-gate struct linkblk *lp = (struct linkblk *)mp->b_cont->b_rptr; 954*7c478bd9Sstevel@tonic-gate 955*7c478bd9Sstevel@tonic-gate /* 956*7c478bd9Sstevel@tonic-gate * Fail if we're already linked. 957*7c478bd9Sstevel@tonic-gate */ 958*7c478bd9Sstevel@tonic-gate if (tmxp->muxq != NULL) { 959*7c478bd9Sstevel@tonic-gate miocnak(q, mp, 0, EINVAL); 960*7c478bd9Sstevel@tonic-gate return; 961*7c478bd9Sstevel@tonic-gate } 962*7c478bd9Sstevel@tonic-gate 963*7c478bd9Sstevel@tonic-gate tmxp->muxq = lp->l_qbot; 964*7c478bd9Sstevel@tonic-gate tmxp->muxq->q_ptr = tmxp; 965*7c478bd9Sstevel@tonic-gate RD(tmxp->muxq)->q_ptr = tmxp; 966*7c478bd9Sstevel@tonic-gate 967*7c478bd9Sstevel@tonic-gate miocack(q, mp, 0, 0); 968*7c478bd9Sstevel@tonic-gate } 969*7c478bd9Sstevel@tonic-gate 970*7c478bd9Sstevel@tonic-gate /* 971*7c478bd9Sstevel@tonic-gate * logdmuxunlink() is called from logdmuxuwput() and is the first of two 972*7c478bd9Sstevel@tonic-gate * functions which process an I_UNLINK ioctl. logdmuxunlink() will determine 973*7c478bd9Sstevel@tonic-gate * the state of logindmux peer linkage and, based on this, control when the 974*7c478bd9Sstevel@tonic-gate * second function, logdmux_finish_unlink(), is called. It's 975*7c478bd9Sstevel@tonic-gate * logdmux_finish_unlink() that's sending the M_IOCACK upstream and 976*7c478bd9Sstevel@tonic-gate * resetting the link state. 977*7c478bd9Sstevel@tonic-gate */ 978*7c478bd9Sstevel@tonic-gate static void 979*7c478bd9Sstevel@tonic-gate logdmuxunlink(queue_t *q, mblk_t *mp) 980*7c478bd9Sstevel@tonic-gate { 981*7c478bd9Sstevel@tonic-gate struct tmx *tmxp = q->q_ptr; 982*7c478bd9Sstevel@tonic-gate unlinkinfo_t *unlinkinfop; 983*7c478bd9Sstevel@tonic-gate 984*7c478bd9Sstevel@tonic-gate /* 985*7c478bd9Sstevel@tonic-gate * If we don't have a peer, just unlink. Note that this check needs 986*7c478bd9Sstevel@tonic-gate * to be done under logdmux_qexch_lock to prevent racing with 987*7c478bd9Sstevel@tonic-gate * LOGDMX_IOC_QEXCHANGE, and we *must* set muxq to NULL prior to 988*7c478bd9Sstevel@tonic-gate * releasing the lock so that LOGDMX_IOC_QEXCHANGE will not consider 989*7c478bd9Sstevel@tonic-gate * us as a possible peer anymore (if it already considers us to be a 990*7c478bd9Sstevel@tonic-gate * peer, then unlinkinfop will not be NULL) -- NULLing muxq precludes 991*7c478bd9Sstevel@tonic-gate * use of logdmux_finish_unlink() here. 992*7c478bd9Sstevel@tonic-gate */ 993*7c478bd9Sstevel@tonic-gate mutex_enter(&logdmux_qexch_lock); 994*7c478bd9Sstevel@tonic-gate unlinkinfop = tmxp->unlinkinfop; 995*7c478bd9Sstevel@tonic-gate if (unlinkinfop == NULL) { 996*7c478bd9Sstevel@tonic-gate ASSERT(tmxp->peerq == NULL); 997*7c478bd9Sstevel@tonic-gate tmxp->muxq = NULL; 998*7c478bd9Sstevel@tonic-gate mutex_exit(&logdmux_qexch_lock); 999*7c478bd9Sstevel@tonic-gate miocack(q, mp, 0, 0); 1000*7c478bd9Sstevel@tonic-gate return; 1001*7c478bd9Sstevel@tonic-gate } 1002*7c478bd9Sstevel@tonic-gate mutex_exit(&logdmux_qexch_lock); 1003*7c478bd9Sstevel@tonic-gate 1004*7c478bd9Sstevel@tonic-gate mutex_enter(&unlinkinfop->state_lock); 1005*7c478bd9Sstevel@tonic-gate 1006*7c478bd9Sstevel@tonic-gate switch (unlinkinfop->state) { 1007*7c478bd9Sstevel@tonic-gate 1008*7c478bd9Sstevel@tonic-gate case LOGDMUX_LINKED: 1009*7c478bd9Sstevel@tonic-gate /* 1010*7c478bd9Sstevel@tonic-gate * We're the first instance to process an I_UNLINK -- 1011*7c478bd9Sstevel@tonic-gate * ie, the peer instance is still there. We'll change 1012*7c478bd9Sstevel@tonic-gate * the state so that only one instance is executing an 1013*7c478bd9Sstevel@tonic-gate * I_UNLINK at any one time. 1014*7c478bd9Sstevel@tonic-gate */ 1015*7c478bd9Sstevel@tonic-gate unlinkinfop->state = LOGDMUX_UNLINK_PENDING; 1016*7c478bd9Sstevel@tonic-gate mutex_exit(&unlinkinfop->state_lock); 1017*7c478bd9Sstevel@tonic-gate /* 1018*7c478bd9Sstevel@tonic-gate * Attach the original M_IOCTL message to a 1019*7c478bd9Sstevel@tonic-gate * LOGDMUX_UNLINK_REQ message and send it to our peer to 1020*7c478bd9Sstevel@tonic-gate * tell it to unlink from us. When it has completed the 1021*7c478bd9Sstevel@tonic-gate * task, it will send us a LOGDMUX_UNLINK_RESP message 1022*7c478bd9Sstevel@tonic-gate * with the original M_IOCTL still attached, which will be 1023*7c478bd9Sstevel@tonic-gate * processed in our logdmuxlrput(). At that point, we will 1024*7c478bd9Sstevel@tonic-gate * call logdmux_finish_unlink() to complete the unlink 1025*7c478bd9Sstevel@tonic-gate * operation using the attached M_IOCTL. 1026*7c478bd9Sstevel@tonic-gate */ 1027*7c478bd9Sstevel@tonic-gate unlinkinfop->prot_mp->b_cont = mp; 1028*7c478bd9Sstevel@tonic-gate /* 1029*7c478bd9Sstevel@tonic-gate * Put the M_CTL directly to the peer's lower RQ. 1030*7c478bd9Sstevel@tonic-gate */ 1031*7c478bd9Sstevel@tonic-gate put(RD(tmxp->peerq), unlinkinfop->prot_mp); 1032*7c478bd9Sstevel@tonic-gate break; 1033*7c478bd9Sstevel@tonic-gate 1034*7c478bd9Sstevel@tonic-gate case LOGDMUX_UNLINK_PENDING: 1035*7c478bd9Sstevel@tonic-gate mutex_exit(&unlinkinfop->state_lock); 1036*7c478bd9Sstevel@tonic-gate /* 1037*7c478bd9Sstevel@tonic-gate * Our peer is actively processing an I_UNLINK itself. 1038*7c478bd9Sstevel@tonic-gate * We have to wait for the peer to complete and we use 1039*7c478bd9Sstevel@tonic-gate * qtimeout as a way to poll for its completion. 1040*7c478bd9Sstevel@tonic-gate * We save a reference to our mblk so that we can send 1041*7c478bd9Sstevel@tonic-gate * it upstream once our peer is done. 1042*7c478bd9Sstevel@tonic-gate */ 1043*7c478bd9Sstevel@tonic-gate tmxp->unlink_mp = mp; 1044*7c478bd9Sstevel@tonic-gate tmxp->utimoutid = qtimeout(q, logdmux_unlink_timer, q, 1045*7c478bd9Sstevel@tonic-gate drv_usectohz(LOGDMUX_POLL_WAIT)); 1046*7c478bd9Sstevel@tonic-gate break; 1047*7c478bd9Sstevel@tonic-gate 1048*7c478bd9Sstevel@tonic-gate case LOGDMUX_UNLINKED: 1049*7c478bd9Sstevel@tonic-gate /* 1050*7c478bd9Sstevel@tonic-gate * Our peer is no longer linked so we can proceed. 1051*7c478bd9Sstevel@tonic-gate */ 1052*7c478bd9Sstevel@tonic-gate mutex_exit(&unlinkinfop->state_lock); 1053*7c478bd9Sstevel@tonic-gate mutex_destroy(&unlinkinfop->state_lock); 1054*7c478bd9Sstevel@tonic-gate freeb(unlinkinfop->prot_mp); 1055*7c478bd9Sstevel@tonic-gate kmem_free(unlinkinfop, sizeof (unlinkinfo_t)); 1056*7c478bd9Sstevel@tonic-gate logdmux_finish_unlink(q, mp); 1057*7c478bd9Sstevel@tonic-gate break; 1058*7c478bd9Sstevel@tonic-gate 1059*7c478bd9Sstevel@tonic-gate default: 1060*7c478bd9Sstevel@tonic-gate mutex_exit(&unlinkinfop->state_lock); 1061*7c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, 1062*7c478bd9Sstevel@tonic-gate "logdmuxunlink: peer linkage is in an unrecognized state"); 1063*7c478bd9Sstevel@tonic-gate break; 1064*7c478bd9Sstevel@tonic-gate } 1065*7c478bd9Sstevel@tonic-gate } 1066*7c478bd9Sstevel@tonic-gate 1067*7c478bd9Sstevel@tonic-gate /* 1068*7c478bd9Sstevel@tonic-gate * Finish the unlink operation. Note that no locks should be held since 1069*7c478bd9Sstevel@tonic-gate * this routine calls into other queues. 1070*7c478bd9Sstevel@tonic-gate */ 1071*7c478bd9Sstevel@tonic-gate static void 1072*7c478bd9Sstevel@tonic-gate logdmux_finish_unlink(queue_t *q, mblk_t *unlink_mp) 1073*7c478bd9Sstevel@tonic-gate { 1074*7c478bd9Sstevel@tonic-gate struct tmx *tmxp = q->q_ptr; 1075*7c478bd9Sstevel@tonic-gate mblk_t *mp; 1076*7c478bd9Sstevel@tonic-gate 1077*7c478bd9Sstevel@tonic-gate /* 1078*7c478bd9Sstevel@tonic-gate * Flush any write side data downstream. 1079*7c478bd9Sstevel@tonic-gate */ 1080*7c478bd9Sstevel@tonic-gate while ((mp = getq(WR(q))) != NULL) 1081*7c478bd9Sstevel@tonic-gate putnext(tmxp->muxq, mp); 1082*7c478bd9Sstevel@tonic-gate 1083*7c478bd9Sstevel@tonic-gate /* 1084*7c478bd9Sstevel@tonic-gate * Note that we do not NULL out q_ptr since another thread (e.g., a 1085*7c478bd9Sstevel@tonic-gate * STREAMS service thread) might call logdmuxlrput() between the time 1086*7c478bd9Sstevel@tonic-gate * we exit the logindmux perimeter and the time the STREAMS framework 1087*7c478bd9Sstevel@tonic-gate * resets q_ptr to stdata (since muxq is set to NULL, any messages 1088*7c478bd9Sstevel@tonic-gate * will just be discarded). 1089*7c478bd9Sstevel@tonic-gate */ 1090*7c478bd9Sstevel@tonic-gate tmxp->muxq = NULL; 1091*7c478bd9Sstevel@tonic-gate tmxp->unlinkinfop = NULL; 1092*7c478bd9Sstevel@tonic-gate tmxp->peerq = NULL; 1093*7c478bd9Sstevel@tonic-gate miocack(q, unlink_mp, 0, 0); 1094*7c478bd9Sstevel@tonic-gate } 1095*7c478bd9Sstevel@tonic-gate 1096*7c478bd9Sstevel@tonic-gate /* 1097*7c478bd9Sstevel@tonic-gate * logdmux_unlink_timer() is executed by qtimeout(). This function will 1098*7c478bd9Sstevel@tonic-gate * check unlinkinfop->state to determine whether the peer has completed 1099*7c478bd9Sstevel@tonic-gate * its I_UNLINK. If it hasn't, we use qtimeout() to initiate another poll. 1100*7c478bd9Sstevel@tonic-gate */ 1101*7c478bd9Sstevel@tonic-gate static void 1102*7c478bd9Sstevel@tonic-gate logdmux_unlink_timer(void *arg) 1103*7c478bd9Sstevel@tonic-gate { 1104*7c478bd9Sstevel@tonic-gate queue_t *q = arg; 1105*7c478bd9Sstevel@tonic-gate struct tmx *tmxp = q->q_ptr; 1106*7c478bd9Sstevel@tonic-gate unlinkinfo_t *unlinkinfop = tmxp->unlinkinfop; 1107*7c478bd9Sstevel@tonic-gate 1108*7c478bd9Sstevel@tonic-gate tmxp->utimoutid = 0; 1109*7c478bd9Sstevel@tonic-gate 1110*7c478bd9Sstevel@tonic-gate mutex_enter(&unlinkinfop->state_lock); 1111*7c478bd9Sstevel@tonic-gate 1112*7c478bd9Sstevel@tonic-gate if (unlinkinfop->state != LOGDMUX_UNLINKED) { 1113*7c478bd9Sstevel@tonic-gate ASSERT(unlinkinfop->state == LOGDMUX_UNLINK_PENDING); 1114*7c478bd9Sstevel@tonic-gate mutex_exit(&unlinkinfop->state_lock); 1115*7c478bd9Sstevel@tonic-gate /* 1116*7c478bd9Sstevel@tonic-gate * We need to wait longer for our peer to complete. 1117*7c478bd9Sstevel@tonic-gate */ 1118*7c478bd9Sstevel@tonic-gate tmxp->utimoutid = qtimeout(q, logdmux_unlink_timer, q, 1119*7c478bd9Sstevel@tonic-gate drv_usectohz(LOGDMUX_POLL_WAIT)); 1120*7c478bd9Sstevel@tonic-gate } else { 1121*7c478bd9Sstevel@tonic-gate /* 1122*7c478bd9Sstevel@tonic-gate * Our peer is no longer linked so we can proceed with 1123*7c478bd9Sstevel@tonic-gate * the cleanup. 1124*7c478bd9Sstevel@tonic-gate */ 1125*7c478bd9Sstevel@tonic-gate mutex_exit(&unlinkinfop->state_lock); 1126*7c478bd9Sstevel@tonic-gate mutex_destroy(&unlinkinfop->state_lock); 1127*7c478bd9Sstevel@tonic-gate freeb(unlinkinfop->prot_mp); 1128*7c478bd9Sstevel@tonic-gate kmem_free(unlinkinfop, sizeof (unlinkinfo_t)); 1129*7c478bd9Sstevel@tonic-gate logdmux_finish_unlink(q, tmxp->unlink_mp); 1130*7c478bd9Sstevel@tonic-gate } 1131*7c478bd9Sstevel@tonic-gate } 1132*7c478bd9Sstevel@tonic-gate 1133*7c478bd9Sstevel@tonic-gate static void 1134*7c478bd9Sstevel@tonic-gate logdmux_timer(void *arg) 1135*7c478bd9Sstevel@tonic-gate { 1136*7c478bd9Sstevel@tonic-gate queue_t *q = arg; 1137*7c478bd9Sstevel@tonic-gate struct tmx *tmxp = q->q_ptr; 1138*7c478bd9Sstevel@tonic-gate 1139*7c478bd9Sstevel@tonic-gate ASSERT(tmxp != NULL); 1140*7c478bd9Sstevel@tonic-gate 1141*7c478bd9Sstevel@tonic-gate if (q->q_flag & QREADR) { 1142*7c478bd9Sstevel@tonic-gate ASSERT(tmxp->rtimoutid != 0); 1143*7c478bd9Sstevel@tonic-gate tmxp->rtimoutid = 0; 1144*7c478bd9Sstevel@tonic-gate } else { 1145*7c478bd9Sstevel@tonic-gate ASSERT(tmxp->wtimoutid != 0); 1146*7c478bd9Sstevel@tonic-gate tmxp->wtimoutid = 0; 1147*7c478bd9Sstevel@tonic-gate } 1148*7c478bd9Sstevel@tonic-gate enableok(q); 1149*7c478bd9Sstevel@tonic-gate qenable(q); 1150*7c478bd9Sstevel@tonic-gate } 1151*7c478bd9Sstevel@tonic-gate 1152*7c478bd9Sstevel@tonic-gate static void 1153*7c478bd9Sstevel@tonic-gate logdmux_buffer(void *arg) 1154*7c478bd9Sstevel@tonic-gate { 1155*7c478bd9Sstevel@tonic-gate queue_t *q = arg; 1156*7c478bd9Sstevel@tonic-gate struct tmx *tmxp = q->q_ptr; 1157*7c478bd9Sstevel@tonic-gate 1158*7c478bd9Sstevel@tonic-gate ASSERT(tmxp != NULL); 1159*7c478bd9Sstevel@tonic-gate 1160*7c478bd9Sstevel@tonic-gate if (q->q_flag & QREADR) { 1161*7c478bd9Sstevel@tonic-gate ASSERT(tmxp->rbufcid != 0); 1162*7c478bd9Sstevel@tonic-gate tmxp->rbufcid = 0; 1163*7c478bd9Sstevel@tonic-gate } else { 1164*7c478bd9Sstevel@tonic-gate ASSERT(tmxp->wbufcid != 0); 1165*7c478bd9Sstevel@tonic-gate tmxp->wbufcid = 0; 1166*7c478bd9Sstevel@tonic-gate } 1167*7c478bd9Sstevel@tonic-gate enableok(q); 1168*7c478bd9Sstevel@tonic-gate qenable(q); 1169*7c478bd9Sstevel@tonic-gate } 1170*7c478bd9Sstevel@tonic-gate 1171*7c478bd9Sstevel@tonic-gate static void 1172*7c478bd9Sstevel@tonic-gate recover(queue_t *q, mblk_t *mp, size_t size) 1173*7c478bd9Sstevel@tonic-gate { 1174*7c478bd9Sstevel@tonic-gate timeout_id_t tid; 1175*7c478bd9Sstevel@tonic-gate bufcall_id_t bid; 1176*7c478bd9Sstevel@tonic-gate struct tmx *tmxp = q->q_ptr; 1177*7c478bd9Sstevel@tonic-gate 1178*7c478bd9Sstevel@tonic-gate /* 1179*7c478bd9Sstevel@tonic-gate * Avoid re-enabling the queue. 1180*7c478bd9Sstevel@tonic-gate */ 1181*7c478bd9Sstevel@tonic-gate ASSERT(queclass(mp) < QPCTL); 1182*7c478bd9Sstevel@tonic-gate ASSERT(WR(q)->q_next == NULL); /* Called from upper queue only */ 1183*7c478bd9Sstevel@tonic-gate noenable(q); 1184*7c478bd9Sstevel@tonic-gate (void) putbq(q, mp); 1185*7c478bd9Sstevel@tonic-gate 1186*7c478bd9Sstevel@tonic-gate /* 1187*7c478bd9Sstevel@tonic-gate * Make sure there is at most one outstanding request per queue. 1188*7c478bd9Sstevel@tonic-gate */ 1189*7c478bd9Sstevel@tonic-gate if (q->q_flag & QREADR) { 1190*7c478bd9Sstevel@tonic-gate if (tmxp->rtimoutid != 0 || tmxp->rbufcid != 0) 1191*7c478bd9Sstevel@tonic-gate return; 1192*7c478bd9Sstevel@tonic-gate } else { 1193*7c478bd9Sstevel@tonic-gate if (tmxp->wtimoutid != 0 || tmxp->wbufcid != 0) 1194*7c478bd9Sstevel@tonic-gate return; 1195*7c478bd9Sstevel@tonic-gate } 1196*7c478bd9Sstevel@tonic-gate if (!(bid = qbufcall(RD(q), size, BPRI_MED, logdmux_buffer, q))) { 1197*7c478bd9Sstevel@tonic-gate tid = qtimeout(RD(q), logdmux_timer, q, drv_usectohz(SIMWAIT)); 1198*7c478bd9Sstevel@tonic-gate if (q->q_flag & QREADR) 1199*7c478bd9Sstevel@tonic-gate tmxp->rtimoutid = tid; 1200*7c478bd9Sstevel@tonic-gate else 1201*7c478bd9Sstevel@tonic-gate tmxp->wtimoutid = tid; 1202*7c478bd9Sstevel@tonic-gate } else { 1203*7c478bd9Sstevel@tonic-gate if (q->q_flag & QREADR) 1204*7c478bd9Sstevel@tonic-gate tmxp->rbufcid = bid; 1205*7c478bd9Sstevel@tonic-gate else 1206*7c478bd9Sstevel@tonic-gate tmxp->wbufcid = bid; 1207*7c478bd9Sstevel@tonic-gate } 1208*7c478bd9Sstevel@tonic-gate } 1209*7c478bd9Sstevel@tonic-gate 1210*7c478bd9Sstevel@tonic-gate static void 1211*7c478bd9Sstevel@tonic-gate flushq_dataonly(queue_t *q) 1212*7c478bd9Sstevel@tonic-gate { 1213*7c478bd9Sstevel@tonic-gate mblk_t *mp, *nmp; 1214*7c478bd9Sstevel@tonic-gate 1215*7c478bd9Sstevel@tonic-gate /* 1216*7c478bd9Sstevel@tonic-gate * Since we are already in the perimeter, and we are not a put-shared 1217*7c478bd9Sstevel@tonic-gate * perimeter, we don't need to freeze the stream or anything to 1218*7c478bd9Sstevel@tonic-gate * be ensured of exclusivity. 1219*7c478bd9Sstevel@tonic-gate */ 1220*7c478bd9Sstevel@tonic-gate mp = q->q_first; 1221*7c478bd9Sstevel@tonic-gate while (mp != NULL) { 1222*7c478bd9Sstevel@tonic-gate if (mp->b_datap->db_type == M_DATA) { 1223*7c478bd9Sstevel@tonic-gate nmp = mp->b_next; 1224*7c478bd9Sstevel@tonic-gate rmvq(q, mp); 1225*7c478bd9Sstevel@tonic-gate freemsg(mp); 1226*7c478bd9Sstevel@tonic-gate mp = nmp; 1227*7c478bd9Sstevel@tonic-gate } else { 1228*7c478bd9Sstevel@tonic-gate mp = mp->b_next; 1229*7c478bd9Sstevel@tonic-gate } 1230*7c478bd9Sstevel@tonic-gate } 1231*7c478bd9Sstevel@tonic-gate } 1232*7c478bd9Sstevel@tonic-gate 1233*7c478bd9Sstevel@tonic-gate /* 1234*7c478bd9Sstevel@tonic-gate * logdmux_alloc_unlinkinfo() is called from logdmuxuwput() during the 1235*7c478bd9Sstevel@tonic-gate * processing of a LOGDMX_IOC_QEXCHANGE ioctl() to allocate the 1236*7c478bd9Sstevel@tonic-gate * unlinkinfo_t which is needed during the processing of an I_UNLINK. 1237*7c478bd9Sstevel@tonic-gate */ 1238*7c478bd9Sstevel@tonic-gate static int 1239*7c478bd9Sstevel@tonic-gate logdmux_alloc_unlinkinfo(struct tmx *t0, struct tmx *t1) 1240*7c478bd9Sstevel@tonic-gate { 1241*7c478bd9Sstevel@tonic-gate unlinkinfo_t *p; 1242*7c478bd9Sstevel@tonic-gate uint_t *messagep; 1243*7c478bd9Sstevel@tonic-gate 1244*7c478bd9Sstevel@tonic-gate if ((p = kmem_zalloc(sizeof (unlinkinfo_t), KM_NOSLEEP)) == NULL) 1245*7c478bd9Sstevel@tonic-gate return (ENOSR); 1246*7c478bd9Sstevel@tonic-gate 1247*7c478bd9Sstevel@tonic-gate if ((p->prot_mp = allocb(sizeof (uint_t), BPRI_MED)) == NULL) { 1248*7c478bd9Sstevel@tonic-gate kmem_free(p, sizeof (unlinkinfo_t)); 1249*7c478bd9Sstevel@tonic-gate return (ENOSR); 1250*7c478bd9Sstevel@tonic-gate } 1251*7c478bd9Sstevel@tonic-gate 1252*7c478bd9Sstevel@tonic-gate DB_TYPE(p->prot_mp) = M_CTL; 1253*7c478bd9Sstevel@tonic-gate messagep = (uint_t *)p->prot_mp->b_wptr; 1254*7c478bd9Sstevel@tonic-gate *messagep = LOGDMUX_UNLINK_REQ; 1255*7c478bd9Sstevel@tonic-gate p->prot_mp->b_wptr += sizeof (*messagep); 1256*7c478bd9Sstevel@tonic-gate p->state = LOGDMUX_LINKED; 1257*7c478bd9Sstevel@tonic-gate mutex_init(&p->state_lock, NULL, MUTEX_DRIVER, NULL); 1258*7c478bd9Sstevel@tonic-gate 1259*7c478bd9Sstevel@tonic-gate t0->unlinkinfop = t1->unlinkinfop = p; 1260*7c478bd9Sstevel@tonic-gate 1261*7c478bd9Sstevel@tonic-gate return (0); 1262*7c478bd9Sstevel@tonic-gate } 1263