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