17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5facf4a8dSllai1 * Common Development and Distribution License (the "License"). 6facf4a8dSllai1 * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*eb5a5c78SSurya Prakki * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved. 237c478bd9Sstevel@tonic-gate */ 247c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 257c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate /* 307c478bd9Sstevel@tonic-gate * Pseudo Terminal Master Driver. 317c478bd9Sstevel@tonic-gate * 327c478bd9Sstevel@tonic-gate * The pseudo-tty subsystem simulates a terminal connection, where the master 337c478bd9Sstevel@tonic-gate * side represents the terminal and the slave represents the user process's 347c478bd9Sstevel@tonic-gate * special device end point. The master device is set up as a cloned device 357c478bd9Sstevel@tonic-gate * where its major device number is the major for the clone device and its minor 367c478bd9Sstevel@tonic-gate * device number is the major for the ptm driver. There are no nodes in the file 377c478bd9Sstevel@tonic-gate * system for master devices. The master pseudo driver is opened using the 387c478bd9Sstevel@tonic-gate * open(2) system call with /dev/ptmx as the device parameter. The clone open 397c478bd9Sstevel@tonic-gate * finds the next available minor device for the ptm major device. 407c478bd9Sstevel@tonic-gate * 417c478bd9Sstevel@tonic-gate * A master device is available only if it and its corresponding slave device 427c478bd9Sstevel@tonic-gate * are not already open. When the master device is opened, the corresponding 437c478bd9Sstevel@tonic-gate * slave device is automatically locked out. Only one open is allowed on a 447c478bd9Sstevel@tonic-gate * master device. Multiple opens are allowed on the slave device. After both 457c478bd9Sstevel@tonic-gate * the master and slave have been opened, the user has two file descriptors 467c478bd9Sstevel@tonic-gate * which are the end points of a full duplex connection composed of two streams 477c478bd9Sstevel@tonic-gate * which are automatically connected at the master and slave drivers. The user 487c478bd9Sstevel@tonic-gate * may then push modules onto either side of the stream pair. 497c478bd9Sstevel@tonic-gate * 507c478bd9Sstevel@tonic-gate * The master and slave drivers pass all messages to their adjacent queues. 517c478bd9Sstevel@tonic-gate * Only the M_FLUSH needs some processing. Because the read queue of one side 527c478bd9Sstevel@tonic-gate * is connected to the write queue of the other, the FLUSHR flag is changed to 537c478bd9Sstevel@tonic-gate * the FLUSHW flag and vice versa. When the master device is closed an M_HANGUP 547c478bd9Sstevel@tonic-gate * message is sent to the slave device which will render the device 557c478bd9Sstevel@tonic-gate * unusable. The process on the slave side gets the EIO when attempting to write 567c478bd9Sstevel@tonic-gate * on that stream but it will be able to read any data remaining on the stream 577c478bd9Sstevel@tonic-gate * head read queue. When all the data has been read, read() returns 0 587c478bd9Sstevel@tonic-gate * indicating that the stream can no longer be used. On the last close of the 597c478bd9Sstevel@tonic-gate * slave device, a 0-length message is sent to the master device. When the 607c478bd9Sstevel@tonic-gate * application on the master side issues a read() or getmsg() and 0 is returned, 617c478bd9Sstevel@tonic-gate * the user of the master device decides whether to issue a close() that 627c478bd9Sstevel@tonic-gate * dismantles the pseudo-terminal subsystem. If the master device is not closed, 637c478bd9Sstevel@tonic-gate * the pseudo-tty subsystem will be available to another user to open the slave 647c478bd9Sstevel@tonic-gate * device. 657c478bd9Sstevel@tonic-gate * 667c478bd9Sstevel@tonic-gate * If O_NONBLOCK or O_NDELAY is set, read on the master side returns -1 with 677c478bd9Sstevel@tonic-gate * errno set to EAGAIN if no data is available, and write returns -1 with errno 687c478bd9Sstevel@tonic-gate * set to EAGAIN if there is internal flow control. 697c478bd9Sstevel@tonic-gate * 707c478bd9Sstevel@tonic-gate * IOCTLS: 717c478bd9Sstevel@tonic-gate * 727c478bd9Sstevel@tonic-gate * ISPTM: determines whether the file descriptor is that of an open master 737c478bd9Sstevel@tonic-gate * device. Return code of zero indicates that the file descriptor 747c478bd9Sstevel@tonic-gate * represents master device. 757c478bd9Sstevel@tonic-gate * 767c478bd9Sstevel@tonic-gate * UNLKPT: unlocks the master and slave devices. It returns 0 on success. On 777c478bd9Sstevel@tonic-gate * failure, the errno is set to EINVAL indicating that the master 787c478bd9Sstevel@tonic-gate * device is not open. 797c478bd9Sstevel@tonic-gate * 80facf4a8dSllai1 * ZONEPT: sets the zone membership of the associated pts device. 81facf4a8dSllai1 * 82facf4a8dSllai1 * GRPPT: sets the group owner of the associated pts device. 837c478bd9Sstevel@tonic-gate * 847c478bd9Sstevel@tonic-gate * Synchronization: 857c478bd9Sstevel@tonic-gate * 867c478bd9Sstevel@tonic-gate * All global data synchronization between ptm/pts is done via global 877c478bd9Sstevel@tonic-gate * ptms_lock mutex which is initialized at system boot time from 887c478bd9Sstevel@tonic-gate * ptms_initspace (called from space.c). 897c478bd9Sstevel@tonic-gate * 907c478bd9Sstevel@tonic-gate * Individual fields of pt_ttys structure (except ptm_rdq, pts_rdq and 917c478bd9Sstevel@tonic-gate * pt_nullmsg) are protected by pt_ttys.pt_lock mutex. 927c478bd9Sstevel@tonic-gate * 937c478bd9Sstevel@tonic-gate * PT_ENTER_READ/PT_ENTER_WRITE are reference counter based read-write locks 947c478bd9Sstevel@tonic-gate * which allow reader locks to be reacquired by the same thread (usual 957c478bd9Sstevel@tonic-gate * reader/writer locks can't be used for that purpose since it is illegal for 967c478bd9Sstevel@tonic-gate * a thread to acquire a lock it already holds, even as a reader). The sole 977c478bd9Sstevel@tonic-gate * purpose of these macros is to guarantee that the peer queue will not 987c478bd9Sstevel@tonic-gate * disappear (due to closing peer) while it is used. It is safe to use 997c478bd9Sstevel@tonic-gate * PT_ENTER_READ/PT_EXIT_READ brackets across calls like putq/putnext (since 1007c478bd9Sstevel@tonic-gate * they are not real locks but reference counts). 1017c478bd9Sstevel@tonic-gate * 1027c478bd9Sstevel@tonic-gate * PT_ENTER_WRITE/PT_EXIT_WRITE brackets are used ONLY in master/slave 1037c478bd9Sstevel@tonic-gate * open/close paths to modify ptm_rdq and pts_rdq fields. These fields should 1047c478bd9Sstevel@tonic-gate * be set to appropriate queues *after* qprocson() is called during open (to 1057c478bd9Sstevel@tonic-gate * prevent peer from accessing the queue with incomplete plumbing) and set to 1067c478bd9Sstevel@tonic-gate * NULL before qprocsoff() is called during close. 1077c478bd9Sstevel@tonic-gate * 1087c478bd9Sstevel@tonic-gate * The pt_nullmsg field is only used in open/close routines and it is also 1097c478bd9Sstevel@tonic-gate * protected by PT_ENTER_WRITE/PT_EXIT_WRITE brackets to avoid extra mutex 1107c478bd9Sstevel@tonic-gate * holds. 1117c478bd9Sstevel@tonic-gate * 1127c478bd9Sstevel@tonic-gate * Lock Ordering: 1137c478bd9Sstevel@tonic-gate * 1147c478bd9Sstevel@tonic-gate * If both ptms_lock and per-pty lock should be held, ptms_lock should always 1157c478bd9Sstevel@tonic-gate * be entered first, followed by per-pty lock. 1167c478bd9Sstevel@tonic-gate * 1177c478bd9Sstevel@tonic-gate * See ptms.h, pts.c and ptms_conf.c for more information. 1187c478bd9Sstevel@tonic-gate */ 1197c478bd9Sstevel@tonic-gate 1207c478bd9Sstevel@tonic-gate #include <sys/types.h> 1217c478bd9Sstevel@tonic-gate #include <sys/param.h> 1227c478bd9Sstevel@tonic-gate #include <sys/file.h> 1237c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 1247c478bd9Sstevel@tonic-gate #include <sys/stream.h> 1257c478bd9Sstevel@tonic-gate #include <sys/stropts.h> 1267c478bd9Sstevel@tonic-gate #include <sys/proc.h> 1277c478bd9Sstevel@tonic-gate #include <sys/errno.h> 1287c478bd9Sstevel@tonic-gate #include <sys/debug.h> 1297c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 1307c478bd9Sstevel@tonic-gate #include <sys/ptms.h> 1317c478bd9Sstevel@tonic-gate #include <sys/stat.h> 1327c478bd9Sstevel@tonic-gate #include <sys/strsun.h> 1337c478bd9Sstevel@tonic-gate #include <sys/systm.h> 1347c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 1357c478bd9Sstevel@tonic-gate #include <sys/conf.h> 1367c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 1377c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 1387c478bd9Sstevel@tonic-gate #include <sys/zone.h> 1397c478bd9Sstevel@tonic-gate 1407c478bd9Sstevel@tonic-gate #ifdef DEBUG 1417c478bd9Sstevel@tonic-gate int ptm_debug = 0; 1427c478bd9Sstevel@tonic-gate #define DBG(a) if (ptm_debug) cmn_err(CE_NOTE, a) 1437c478bd9Sstevel@tonic-gate #else 1447c478bd9Sstevel@tonic-gate #define DBG(a) 1457c478bd9Sstevel@tonic-gate #endif 1467c478bd9Sstevel@tonic-gate 1477c478bd9Sstevel@tonic-gate static int ptmopen(queue_t *, dev_t *, int, int, cred_t *); 1487c478bd9Sstevel@tonic-gate static int ptmclose(queue_t *, int, cred_t *); 1497c478bd9Sstevel@tonic-gate static void ptmwput(queue_t *, mblk_t *); 1507c478bd9Sstevel@tonic-gate static void ptmrsrv(queue_t *); 1517c478bd9Sstevel@tonic-gate static void ptmwsrv(queue_t *); 1527c478bd9Sstevel@tonic-gate 1537c478bd9Sstevel@tonic-gate /* 1547c478bd9Sstevel@tonic-gate * Master Stream Pseudo Terminal Module: stream data structure definitions 1557c478bd9Sstevel@tonic-gate */ 1567c478bd9Sstevel@tonic-gate 1577c478bd9Sstevel@tonic-gate static struct module_info ptm_info = { 1587c478bd9Sstevel@tonic-gate 0xdead, 1597c478bd9Sstevel@tonic-gate "ptm", 1607c478bd9Sstevel@tonic-gate 0, 1617c478bd9Sstevel@tonic-gate 512, 1627c478bd9Sstevel@tonic-gate 512, 1637c478bd9Sstevel@tonic-gate 128 1647c478bd9Sstevel@tonic-gate }; 1657c478bd9Sstevel@tonic-gate 1667c478bd9Sstevel@tonic-gate static struct qinit ptmrint = { 1677c478bd9Sstevel@tonic-gate NULL, 1687c478bd9Sstevel@tonic-gate (int (*)()) ptmrsrv, 1697c478bd9Sstevel@tonic-gate ptmopen, 1707c478bd9Sstevel@tonic-gate ptmclose, 1717c478bd9Sstevel@tonic-gate NULL, 1727c478bd9Sstevel@tonic-gate &ptm_info, 1737c478bd9Sstevel@tonic-gate NULL 1747c478bd9Sstevel@tonic-gate }; 1757c478bd9Sstevel@tonic-gate 1767c478bd9Sstevel@tonic-gate static struct qinit ptmwint = { 1777c478bd9Sstevel@tonic-gate (int (*)()) ptmwput, 1787c478bd9Sstevel@tonic-gate (int (*)()) ptmwsrv, 1797c478bd9Sstevel@tonic-gate NULL, 1807c478bd9Sstevel@tonic-gate NULL, 1817c478bd9Sstevel@tonic-gate NULL, 1827c478bd9Sstevel@tonic-gate &ptm_info, 1837c478bd9Sstevel@tonic-gate NULL 1847c478bd9Sstevel@tonic-gate }; 1857c478bd9Sstevel@tonic-gate 1867c478bd9Sstevel@tonic-gate static struct streamtab ptminfo = { 1877c478bd9Sstevel@tonic-gate &ptmrint, 1887c478bd9Sstevel@tonic-gate &ptmwint, 1897c478bd9Sstevel@tonic-gate NULL, 1907c478bd9Sstevel@tonic-gate NULL 1917c478bd9Sstevel@tonic-gate }; 1927c478bd9Sstevel@tonic-gate 1937c478bd9Sstevel@tonic-gate static int ptm_attach(dev_info_t *, ddi_attach_cmd_t); 1947c478bd9Sstevel@tonic-gate static int ptm_detach(dev_info_t *, ddi_detach_cmd_t); 1957c478bd9Sstevel@tonic-gate static int ptm_devinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 1967c478bd9Sstevel@tonic-gate 1977c478bd9Sstevel@tonic-gate static dev_info_t *ptm_dip; /* private devinfo pointer */ 1987c478bd9Sstevel@tonic-gate 1997c478bd9Sstevel@tonic-gate /* 2007c478bd9Sstevel@tonic-gate * this will define (struct cb_ops cb_ptm_ops) and (struct dev_ops ptm_ops) 2017c478bd9Sstevel@tonic-gate */ 2027c478bd9Sstevel@tonic-gate DDI_DEFINE_STREAM_OPS(ptm_ops, nulldev, nulldev, ptm_attach, ptm_detach, 20319397407SSherry Moore nodev, ptm_devinfo, D_MP, &ptminfo, ddi_quiesce_not_supported); 2047c478bd9Sstevel@tonic-gate 2057c478bd9Sstevel@tonic-gate /* 2067c478bd9Sstevel@tonic-gate * Module linkage information for the kernel. 2077c478bd9Sstevel@tonic-gate */ 2087c478bd9Sstevel@tonic-gate 2097c478bd9Sstevel@tonic-gate static struct modldrv modldrv = { 2107c478bd9Sstevel@tonic-gate &mod_driverops, /* Type of module. This one is a pseudo driver */ 21119397407SSherry Moore "Master streams driver 'ptm'", 2127c478bd9Sstevel@tonic-gate &ptm_ops, /* driver ops */ 2137c478bd9Sstevel@tonic-gate }; 2147c478bd9Sstevel@tonic-gate 2157c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 2167c478bd9Sstevel@tonic-gate MODREV_1, 2177c478bd9Sstevel@tonic-gate &modldrv, 2187c478bd9Sstevel@tonic-gate NULL 2197c478bd9Sstevel@tonic-gate }; 2207c478bd9Sstevel@tonic-gate 2217c478bd9Sstevel@tonic-gate int 2227c478bd9Sstevel@tonic-gate _init(void) 2237c478bd9Sstevel@tonic-gate { 2247c478bd9Sstevel@tonic-gate int rc; 2257c478bd9Sstevel@tonic-gate 2267c478bd9Sstevel@tonic-gate if ((rc = mod_install(&modlinkage)) == 0) 2277c478bd9Sstevel@tonic-gate ptms_init(); 2287c478bd9Sstevel@tonic-gate return (rc); 2297c478bd9Sstevel@tonic-gate } 2307c478bd9Sstevel@tonic-gate 2317c478bd9Sstevel@tonic-gate int 2327c478bd9Sstevel@tonic-gate _fini(void) 2337c478bd9Sstevel@tonic-gate { 2347c478bd9Sstevel@tonic-gate return (mod_remove(&modlinkage)); 2357c478bd9Sstevel@tonic-gate } 2367c478bd9Sstevel@tonic-gate 2377c478bd9Sstevel@tonic-gate int 2387c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 2397c478bd9Sstevel@tonic-gate { 2407c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 2417c478bd9Sstevel@tonic-gate } 2427c478bd9Sstevel@tonic-gate 2437c478bd9Sstevel@tonic-gate static int 2447c478bd9Sstevel@tonic-gate ptm_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 2457c478bd9Sstevel@tonic-gate { 2467c478bd9Sstevel@tonic-gate if (cmd != DDI_ATTACH) 2477c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 2487c478bd9Sstevel@tonic-gate 2497c478bd9Sstevel@tonic-gate if (ddi_create_minor_node(devi, "ptmajor", S_IFCHR, 2507c478bd9Sstevel@tonic-gate 0, DDI_PSEUDO, NULL) == DDI_FAILURE) { 2517c478bd9Sstevel@tonic-gate ddi_remove_minor_node(devi, NULL); 2527c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 2537c478bd9Sstevel@tonic-gate } 2547c478bd9Sstevel@tonic-gate if (ddi_create_minor_node(devi, "ptmx", S_IFCHR, 2557c478bd9Sstevel@tonic-gate 0, DDI_PSEUDO, CLONE_DEV) == DDI_FAILURE) { 2567c478bd9Sstevel@tonic-gate ddi_remove_minor_node(devi, NULL); 2577c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 2587c478bd9Sstevel@tonic-gate } 2597c478bd9Sstevel@tonic-gate ptm_dip = devi; 2607c478bd9Sstevel@tonic-gate 2617c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2627c478bd9Sstevel@tonic-gate } 2637c478bd9Sstevel@tonic-gate 2647c478bd9Sstevel@tonic-gate static int 2657c478bd9Sstevel@tonic-gate ptm_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) 2667c478bd9Sstevel@tonic-gate { 2677c478bd9Sstevel@tonic-gate if (cmd != DDI_DETACH) 2687c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 2697c478bd9Sstevel@tonic-gate 2707c478bd9Sstevel@tonic-gate ddi_remove_minor_node(devi, NULL); 2717c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2727c478bd9Sstevel@tonic-gate } 2737c478bd9Sstevel@tonic-gate 2747c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2757c478bd9Sstevel@tonic-gate static int 2767c478bd9Sstevel@tonic-gate ptm_devinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 2777c478bd9Sstevel@tonic-gate void **result) 2787c478bd9Sstevel@tonic-gate { 2797c478bd9Sstevel@tonic-gate int error; 2807c478bd9Sstevel@tonic-gate 2817c478bd9Sstevel@tonic-gate switch (infocmd) { 2827c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 2837c478bd9Sstevel@tonic-gate if (ptm_dip == NULL) { 2847c478bd9Sstevel@tonic-gate error = DDI_FAILURE; 2857c478bd9Sstevel@tonic-gate } else { 2867c478bd9Sstevel@tonic-gate *result = (void *)ptm_dip; 2877c478bd9Sstevel@tonic-gate error = DDI_SUCCESS; 2887c478bd9Sstevel@tonic-gate } 2897c478bd9Sstevel@tonic-gate break; 2907c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 2917c478bd9Sstevel@tonic-gate *result = (void *)0; 2927c478bd9Sstevel@tonic-gate error = DDI_SUCCESS; 2937c478bd9Sstevel@tonic-gate break; 2947c478bd9Sstevel@tonic-gate default: 2957c478bd9Sstevel@tonic-gate error = DDI_FAILURE; 2967c478bd9Sstevel@tonic-gate } 2977c478bd9Sstevel@tonic-gate return (error); 2987c478bd9Sstevel@tonic-gate } 2997c478bd9Sstevel@tonic-gate 3007c478bd9Sstevel@tonic-gate 3017c478bd9Sstevel@tonic-gate /* ARGSUSED */ 3027c478bd9Sstevel@tonic-gate /* 3037c478bd9Sstevel@tonic-gate * Open a minor of the master device. Store the write queue pointer and set the 3047c478bd9Sstevel@tonic-gate * pt_state field to (PTMOPEN | PTLOCK). 3057c478bd9Sstevel@tonic-gate * This code will work properly with both clone opens and direct opens of the 3067c478bd9Sstevel@tonic-gate * master device. 3077c478bd9Sstevel@tonic-gate */ 3087c478bd9Sstevel@tonic-gate static int 3097c478bd9Sstevel@tonic-gate ptmopen( 3107c478bd9Sstevel@tonic-gate queue_t *rqp, /* pointer to the read side queue */ 3117c478bd9Sstevel@tonic-gate dev_t *devp, /* pointer to stream tail's dev */ 3127c478bd9Sstevel@tonic-gate int oflag, /* the user open(2) supplied flags */ 3137c478bd9Sstevel@tonic-gate int sflag, /* open state flag */ 3147c478bd9Sstevel@tonic-gate cred_t *credp) /* credentials */ 3157c478bd9Sstevel@tonic-gate { 3167c478bd9Sstevel@tonic-gate struct pt_ttys *ptmp; 3177c478bd9Sstevel@tonic-gate mblk_t *mop; /* ptr to a setopts message block */ 3187c478bd9Sstevel@tonic-gate struct stroptions *sop; 3197c478bd9Sstevel@tonic-gate minor_t dminor = getminor(*devp); 3207c478bd9Sstevel@tonic-gate 3217c478bd9Sstevel@tonic-gate /* Allow reopen */ 3227c478bd9Sstevel@tonic-gate if (rqp->q_ptr != NULL) 3237c478bd9Sstevel@tonic-gate return (0); 3247c478bd9Sstevel@tonic-gate 3257c478bd9Sstevel@tonic-gate if (sflag & MODOPEN) 3267c478bd9Sstevel@tonic-gate return (ENXIO); 3277c478bd9Sstevel@tonic-gate 3287c478bd9Sstevel@tonic-gate if (!(sflag & CLONEOPEN) && dminor != 0) { 3297c478bd9Sstevel@tonic-gate /* 3307c478bd9Sstevel@tonic-gate * This is a direct open to specific master device through an 3317c478bd9Sstevel@tonic-gate * artificially created entry with specific minor in 3327c478bd9Sstevel@tonic-gate * /dev/directory. Such behavior is not supported. 3337c478bd9Sstevel@tonic-gate */ 3347c478bd9Sstevel@tonic-gate return (ENXIO); 3357c478bd9Sstevel@tonic-gate } 3367c478bd9Sstevel@tonic-gate 3377c478bd9Sstevel@tonic-gate /* 338facf4a8dSllai1 * The master open requires that the slave be attached 339facf4a8dSllai1 * before it returns so that attempts to open the slave will 340facf4a8dSllai1 * succeeed 3417c478bd9Sstevel@tonic-gate */ 342facf4a8dSllai1 if (ptms_attach_slave() != 0) { 343facf4a8dSllai1 return (ENXIO); 344facf4a8dSllai1 } 3457c478bd9Sstevel@tonic-gate 3467c478bd9Sstevel@tonic-gate mop = allocb(sizeof (struct stroptions), BPRI_MED); 3477c478bd9Sstevel@tonic-gate if (mop == NULL) { 3487c478bd9Sstevel@tonic-gate DDBG("ptmopen(): mop allocation failed\n", 0); 3497c478bd9Sstevel@tonic-gate return (ENOMEM); 3507c478bd9Sstevel@tonic-gate } 3517c478bd9Sstevel@tonic-gate 3527c478bd9Sstevel@tonic-gate if ((ptmp = pt_ttys_alloc()) == NULL) { 3537c478bd9Sstevel@tonic-gate DDBG("ptmopen(): pty allocation failed\n", 0); 3547c478bd9Sstevel@tonic-gate freemsg(mop); 3557c478bd9Sstevel@tonic-gate return (ENOMEM); 3567c478bd9Sstevel@tonic-gate } 3577c478bd9Sstevel@tonic-gate 3587c478bd9Sstevel@tonic-gate dminor = ptmp->pt_minor; 3597c478bd9Sstevel@tonic-gate 3607c478bd9Sstevel@tonic-gate DDBGP("ptmopen(): allocated ptmp %p\n", (uintptr_t)ptmp); 3617c478bd9Sstevel@tonic-gate DDBG("ptmopen(): allocated minor %d\n", dminor); 3627c478bd9Sstevel@tonic-gate 3637c478bd9Sstevel@tonic-gate WR(rqp)->q_ptr = rqp->q_ptr = ptmp; 3647c478bd9Sstevel@tonic-gate 3657c478bd9Sstevel@tonic-gate qprocson(rqp); 3667c478bd9Sstevel@tonic-gate 3677c478bd9Sstevel@tonic-gate /* Allow slave to send messages to master */ 3687c478bd9Sstevel@tonic-gate PT_ENTER_WRITE(ptmp); 3697c478bd9Sstevel@tonic-gate ptmp->ptm_rdq = rqp; 3707c478bd9Sstevel@tonic-gate PT_EXIT_WRITE(ptmp); 3717c478bd9Sstevel@tonic-gate 3727c478bd9Sstevel@tonic-gate /* 3737c478bd9Sstevel@tonic-gate * set up hi/lo water marks on stream head read queue 3747c478bd9Sstevel@tonic-gate * and add controlling tty if not set 3757c478bd9Sstevel@tonic-gate */ 3767c478bd9Sstevel@tonic-gate mop->b_datap->db_type = M_SETOPTS; 3777c478bd9Sstevel@tonic-gate mop->b_wptr += sizeof (struct stroptions); 3787c478bd9Sstevel@tonic-gate sop = (struct stroptions *)mop->b_rptr; 3797c478bd9Sstevel@tonic-gate if (oflag & FNOCTTY) 3807c478bd9Sstevel@tonic-gate sop->so_flags = SO_HIWAT | SO_LOWAT; 3817c478bd9Sstevel@tonic-gate else 3827c478bd9Sstevel@tonic-gate sop->so_flags = SO_HIWAT | SO_LOWAT | SO_ISTTY; 3837c478bd9Sstevel@tonic-gate sop->so_hiwat = 512; 3847c478bd9Sstevel@tonic-gate sop->so_lowat = 256; 3857c478bd9Sstevel@tonic-gate putnext(rqp, mop); 3867c478bd9Sstevel@tonic-gate 3877c478bd9Sstevel@tonic-gate /* 3887c478bd9Sstevel@tonic-gate * The input, devp, is a major device number, the output is put 3897c478bd9Sstevel@tonic-gate * into the same parm as a major,minor pair. 3907c478bd9Sstevel@tonic-gate */ 3917c478bd9Sstevel@tonic-gate *devp = makedevice(getmajor(*devp), dminor); 3927c478bd9Sstevel@tonic-gate 3937c478bd9Sstevel@tonic-gate return (0); 3947c478bd9Sstevel@tonic-gate } 3957c478bd9Sstevel@tonic-gate 3967c478bd9Sstevel@tonic-gate 3977c478bd9Sstevel@tonic-gate /* 3987c478bd9Sstevel@tonic-gate * Find the address to private data identifying the slave's write queue. 3997c478bd9Sstevel@tonic-gate * Send a hang-up message up the slave's read queue to designate the 4007c478bd9Sstevel@tonic-gate * master/slave pair is tearing down. Uattach the master and slave by 4017c478bd9Sstevel@tonic-gate * nulling out the write queue fields in the private data structure. 4027c478bd9Sstevel@tonic-gate * Finally, unlock the master/slave pair and mark the master as closed. 4037c478bd9Sstevel@tonic-gate */ 4047c478bd9Sstevel@tonic-gate /*ARGSUSED1*/ 4057c478bd9Sstevel@tonic-gate static int 4067c478bd9Sstevel@tonic-gate ptmclose(queue_t *rqp, int flag, cred_t *credp) 4077c478bd9Sstevel@tonic-gate { 4087c478bd9Sstevel@tonic-gate struct pt_ttys *ptmp; 4097c478bd9Sstevel@tonic-gate queue_t *pts_rdq; 4107c478bd9Sstevel@tonic-gate 4117c478bd9Sstevel@tonic-gate ASSERT(rqp->q_ptr); 4127c478bd9Sstevel@tonic-gate 4137c478bd9Sstevel@tonic-gate ptmp = (struct pt_ttys *)rqp->q_ptr; 4147c478bd9Sstevel@tonic-gate PT_ENTER_READ(ptmp); 4157c478bd9Sstevel@tonic-gate if (ptmp->pts_rdq) { 4167c478bd9Sstevel@tonic-gate pts_rdq = ptmp->pts_rdq; 4177c478bd9Sstevel@tonic-gate if (pts_rdq->q_next) { 4187c478bd9Sstevel@tonic-gate DBG(("send hangup message to slave\n")); 4197c478bd9Sstevel@tonic-gate (void) putnextctl(pts_rdq, M_HANGUP); 4207c478bd9Sstevel@tonic-gate } 4217c478bd9Sstevel@tonic-gate } 4227c478bd9Sstevel@tonic-gate PT_EXIT_READ(ptmp); 4237c478bd9Sstevel@tonic-gate /* 4247c478bd9Sstevel@tonic-gate * ptm_rdq should be cleared before call to qprocsoff() to prevent pts 4257c478bd9Sstevel@tonic-gate * write procedure to attempt using ptm_rdq after qprocsoff. 4267c478bd9Sstevel@tonic-gate */ 4277c478bd9Sstevel@tonic-gate PT_ENTER_WRITE(ptmp); 4287c478bd9Sstevel@tonic-gate ptmp->ptm_rdq = NULL; 4297c478bd9Sstevel@tonic-gate freemsg(ptmp->pt_nullmsg); 4307c478bd9Sstevel@tonic-gate ptmp->pt_nullmsg = NULL; 4317c478bd9Sstevel@tonic-gate /* 4327c478bd9Sstevel@tonic-gate * qenable slave side write queue so that it can flush 4337c478bd9Sstevel@tonic-gate * its messages as master's read queue is going away 4347c478bd9Sstevel@tonic-gate */ 4357c478bd9Sstevel@tonic-gate if (ptmp->pts_rdq) 4367c478bd9Sstevel@tonic-gate qenable(WR(ptmp->pts_rdq)); 4377c478bd9Sstevel@tonic-gate PT_EXIT_WRITE(ptmp); 4387c478bd9Sstevel@tonic-gate 4397c478bd9Sstevel@tonic-gate qprocsoff(rqp); 4407c478bd9Sstevel@tonic-gate 4417c478bd9Sstevel@tonic-gate /* Finish the close */ 4427c478bd9Sstevel@tonic-gate rqp->q_ptr = NULL; 4437c478bd9Sstevel@tonic-gate WR(rqp)->q_ptr = NULL; 4447c478bd9Sstevel@tonic-gate 4457c478bd9Sstevel@tonic-gate ptms_close(ptmp, PTMOPEN | PTLOCK); 4467c478bd9Sstevel@tonic-gate 4477c478bd9Sstevel@tonic-gate return (0); 4487c478bd9Sstevel@tonic-gate } 4497c478bd9Sstevel@tonic-gate 4507c478bd9Sstevel@tonic-gate /* 4517c478bd9Sstevel@tonic-gate * The wput procedure will only handle ioctl and flush messages. 4527c478bd9Sstevel@tonic-gate */ 4537c478bd9Sstevel@tonic-gate static void 4547c478bd9Sstevel@tonic-gate ptmwput(queue_t *qp, mblk_t *mp) 4557c478bd9Sstevel@tonic-gate { 4567c478bd9Sstevel@tonic-gate struct pt_ttys *ptmp; 4577c478bd9Sstevel@tonic-gate struct iocblk *iocp; 4587c478bd9Sstevel@tonic-gate 4597c478bd9Sstevel@tonic-gate DBG(("entering ptmwput\n")); 4607c478bd9Sstevel@tonic-gate ASSERT(qp->q_ptr); 4617c478bd9Sstevel@tonic-gate 4627c478bd9Sstevel@tonic-gate ptmp = (struct pt_ttys *)qp->q_ptr; 4637c478bd9Sstevel@tonic-gate PT_ENTER_READ(ptmp); 4647c478bd9Sstevel@tonic-gate 4657c478bd9Sstevel@tonic-gate switch (mp->b_datap->db_type) { 4667c478bd9Sstevel@tonic-gate /* 4677c478bd9Sstevel@tonic-gate * if write queue request, flush master's write 4687c478bd9Sstevel@tonic-gate * queue and send FLUSHR up slave side. If read 4697c478bd9Sstevel@tonic-gate * queue request, convert to FLUSHW and putnext(). 4707c478bd9Sstevel@tonic-gate */ 4717c478bd9Sstevel@tonic-gate case M_FLUSH: 4727c478bd9Sstevel@tonic-gate { 4737c478bd9Sstevel@tonic-gate unsigned char flush_flg = 0; 4747c478bd9Sstevel@tonic-gate 4757c478bd9Sstevel@tonic-gate DBG(("ptm got flush request\n")); 4767c478bd9Sstevel@tonic-gate if (*mp->b_rptr & FLUSHW) { 4777c478bd9Sstevel@tonic-gate DBG(("got FLUSHW, flush ptm write Q\n")); 4787c478bd9Sstevel@tonic-gate if (*mp->b_rptr & FLUSHBAND) 4797c478bd9Sstevel@tonic-gate /* 4807c478bd9Sstevel@tonic-gate * if it is a FLUSHBAND, do flushband. 4817c478bd9Sstevel@tonic-gate */ 4827c478bd9Sstevel@tonic-gate flushband(qp, *(mp->b_rptr + 1), 4837c478bd9Sstevel@tonic-gate FLUSHDATA); 4847c478bd9Sstevel@tonic-gate else 4857c478bd9Sstevel@tonic-gate flushq(qp, FLUSHDATA); 4867c478bd9Sstevel@tonic-gate flush_flg = (*mp->b_rptr & ~FLUSHW) | FLUSHR; 4877c478bd9Sstevel@tonic-gate } 4887c478bd9Sstevel@tonic-gate if (*mp->b_rptr & FLUSHR) { 4897c478bd9Sstevel@tonic-gate DBG(("got FLUSHR, set FLUSHW\n")); 4907c478bd9Sstevel@tonic-gate flush_flg |= (*mp->b_rptr & ~FLUSHR) | FLUSHW; 4917c478bd9Sstevel@tonic-gate } 4927c478bd9Sstevel@tonic-gate if (flush_flg != 0 && ptmp->pts_rdq && 4937c478bd9Sstevel@tonic-gate !(ptmp->pt_state & PTLOCK)) { 4947c478bd9Sstevel@tonic-gate DBG(("putnext to pts\n")); 4957c478bd9Sstevel@tonic-gate *mp->b_rptr = flush_flg; 4967c478bd9Sstevel@tonic-gate putnext(ptmp->pts_rdq, mp); 4977c478bd9Sstevel@tonic-gate } else 4987c478bd9Sstevel@tonic-gate freemsg(mp); 4997c478bd9Sstevel@tonic-gate break; 5007c478bd9Sstevel@tonic-gate } 5017c478bd9Sstevel@tonic-gate 5027c478bd9Sstevel@tonic-gate case M_IOCTL: 5037c478bd9Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 5047c478bd9Sstevel@tonic-gate switch (iocp->ioc_cmd) { 5057c478bd9Sstevel@tonic-gate default: 5067c478bd9Sstevel@tonic-gate if ((ptmp->pt_state & PTLOCK) || 5077c478bd9Sstevel@tonic-gate (ptmp->pts_rdq == NULL)) { 5087c478bd9Sstevel@tonic-gate DBG(("got M_IOCTL but no slave\n")); 5097c478bd9Sstevel@tonic-gate miocnak(qp, mp, 0, EINVAL); 5107c478bd9Sstevel@tonic-gate PT_EXIT_READ(ptmp); 5117c478bd9Sstevel@tonic-gate return; 5127c478bd9Sstevel@tonic-gate } 5137c478bd9Sstevel@tonic-gate (void) putq(qp, mp); 5147c478bd9Sstevel@tonic-gate break; 5157c478bd9Sstevel@tonic-gate case UNLKPT: 5167c478bd9Sstevel@tonic-gate mutex_enter(&ptmp->pt_lock); 5177c478bd9Sstevel@tonic-gate ptmp->pt_state &= ~PTLOCK; 5187c478bd9Sstevel@tonic-gate mutex_exit(&ptmp->pt_lock); 5197c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/ 5207c478bd9Sstevel@tonic-gate case ISPTM: 5217c478bd9Sstevel@tonic-gate DBG(("ack the UNLKPT/ISPTM\n")); 5227c478bd9Sstevel@tonic-gate miocack(qp, mp, 0, 0); 5237c478bd9Sstevel@tonic-gate break; 5247c478bd9Sstevel@tonic-gate case ZONEPT: 5257c478bd9Sstevel@tonic-gate { 5267c478bd9Sstevel@tonic-gate zoneid_t z; 5277c478bd9Sstevel@tonic-gate int error; 5287c478bd9Sstevel@tonic-gate 5297c478bd9Sstevel@tonic-gate if ((error = drv_priv(iocp->ioc_cr)) != 0) { 5307c478bd9Sstevel@tonic-gate miocnak(qp, mp, 0, error); 5317c478bd9Sstevel@tonic-gate break; 5327c478bd9Sstevel@tonic-gate } 5337c478bd9Sstevel@tonic-gate if ((error = miocpullup(mp, sizeof (zoneid_t))) != 0) { 5347c478bd9Sstevel@tonic-gate miocnak(qp, mp, 0, error); 5357c478bd9Sstevel@tonic-gate break; 5367c478bd9Sstevel@tonic-gate } 5377c478bd9Sstevel@tonic-gate z = *((zoneid_t *)mp->b_cont->b_rptr); 5387c478bd9Sstevel@tonic-gate if (z < MIN_ZONEID || z > MAX_ZONEID) { 5397c478bd9Sstevel@tonic-gate miocnak(qp, mp, 0, EINVAL); 5407c478bd9Sstevel@tonic-gate break; 5417c478bd9Sstevel@tonic-gate } 5427c478bd9Sstevel@tonic-gate 5437c478bd9Sstevel@tonic-gate mutex_enter(&ptmp->pt_lock); 5447c478bd9Sstevel@tonic-gate ptmp->pt_zoneid = z; 5457c478bd9Sstevel@tonic-gate mutex_exit(&ptmp->pt_lock); 5467c478bd9Sstevel@tonic-gate miocack(qp, mp, 0, 0); 5477c478bd9Sstevel@tonic-gate break; 5487c478bd9Sstevel@tonic-gate } 54949e92448Svikram case OWNERPT: 550facf4a8dSllai1 { 551facf4a8dSllai1 pt_own_t *ptop; 552facf4a8dSllai1 int error; 553bda89588Sjp151216 zone_t *zone; 554facf4a8dSllai1 555facf4a8dSllai1 if ((error = miocpullup(mp, sizeof (pt_own_t))) != 0) { 556facf4a8dSllai1 miocnak(qp, mp, 0, error); 557facf4a8dSllai1 break; 558facf4a8dSllai1 } 559facf4a8dSllai1 560bda89588Sjp151216 zone = zone_find_by_id(ptmp->pt_zoneid); 561facf4a8dSllai1 ptop = (pt_own_t *)mp->b_cont->b_rptr; 562facf4a8dSllai1 563bda89588Sjp151216 if (!VALID_UID(ptop->pto_ruid, zone) || 564bda89588Sjp151216 !VALID_GID(ptop->pto_rgid, zone)) { 565bda89588Sjp151216 zone_rele(zone); 566facf4a8dSllai1 miocnak(qp, mp, 0, EINVAL); 567facf4a8dSllai1 break; 568facf4a8dSllai1 } 569bda89588Sjp151216 zone_rele(zone); 570facf4a8dSllai1 mutex_enter(&ptmp->pt_lock); 571facf4a8dSllai1 ptmp->pt_ruid = ptop->pto_ruid; 572facf4a8dSllai1 ptmp->pt_rgid = ptop->pto_rgid; 573facf4a8dSllai1 mutex_exit(&ptmp->pt_lock); 574facf4a8dSllai1 miocack(qp, mp, 0, 0); 575facf4a8dSllai1 break; 576facf4a8dSllai1 } 5777c478bd9Sstevel@tonic-gate } 5787c478bd9Sstevel@tonic-gate break; 5797c478bd9Sstevel@tonic-gate 5807c478bd9Sstevel@tonic-gate case M_READ: 5817c478bd9Sstevel@tonic-gate /* Caused by ldterm - can not pass to slave */ 5827c478bd9Sstevel@tonic-gate freemsg(mp); 5837c478bd9Sstevel@tonic-gate break; 5847c478bd9Sstevel@tonic-gate 5857c478bd9Sstevel@tonic-gate /* 5867c478bd9Sstevel@tonic-gate * send other messages to slave 5877c478bd9Sstevel@tonic-gate */ 5887c478bd9Sstevel@tonic-gate default: 5897c478bd9Sstevel@tonic-gate if ((ptmp->pt_state & PTLOCK) || (ptmp->pts_rdq == NULL)) { 5907c478bd9Sstevel@tonic-gate DBG(("got msg. but no slave\n")); 5917c478bd9Sstevel@tonic-gate mp = mexchange(NULL, mp, 2, M_ERROR, -1); 5927c478bd9Sstevel@tonic-gate if (mp != NULL) { 5937c478bd9Sstevel@tonic-gate mp->b_rptr[0] = NOERROR; 5947c478bd9Sstevel@tonic-gate mp->b_rptr[1] = EINVAL; 5957c478bd9Sstevel@tonic-gate qreply(qp, mp); 5967c478bd9Sstevel@tonic-gate } 5977c478bd9Sstevel@tonic-gate PT_EXIT_READ(ptmp); 5987c478bd9Sstevel@tonic-gate return; 5997c478bd9Sstevel@tonic-gate } 6007c478bd9Sstevel@tonic-gate DBG(("put msg on master's write queue\n")); 6017c478bd9Sstevel@tonic-gate (void) putq(qp, mp); 6027c478bd9Sstevel@tonic-gate break; 6037c478bd9Sstevel@tonic-gate } 6047c478bd9Sstevel@tonic-gate DBG(("return from ptmwput()\n")); 6057c478bd9Sstevel@tonic-gate PT_EXIT_READ(ptmp); 6067c478bd9Sstevel@tonic-gate } 6077c478bd9Sstevel@tonic-gate 6087c478bd9Sstevel@tonic-gate 6097c478bd9Sstevel@tonic-gate /* 6107c478bd9Sstevel@tonic-gate * enable the write side of the slave. This triggers the 6117c478bd9Sstevel@tonic-gate * slave to send any messages queued on its write side to 6127c478bd9Sstevel@tonic-gate * the read side of this master. 6137c478bd9Sstevel@tonic-gate */ 6147c478bd9Sstevel@tonic-gate static void 6157c478bd9Sstevel@tonic-gate ptmrsrv(queue_t *qp) 6167c478bd9Sstevel@tonic-gate { 6177c478bd9Sstevel@tonic-gate struct pt_ttys *ptmp; 6187c478bd9Sstevel@tonic-gate 6197c478bd9Sstevel@tonic-gate DBG(("entering ptmrsrv\n")); 6207c478bd9Sstevel@tonic-gate ASSERT(qp->q_ptr); 6217c478bd9Sstevel@tonic-gate 6227c478bd9Sstevel@tonic-gate ptmp = (struct pt_ttys *)qp->q_ptr; 6237c478bd9Sstevel@tonic-gate PT_ENTER_READ(ptmp); 6247c478bd9Sstevel@tonic-gate if (ptmp->pts_rdq) { 6257c478bd9Sstevel@tonic-gate qenable(WR(ptmp->pts_rdq)); 6267c478bd9Sstevel@tonic-gate } 6277c478bd9Sstevel@tonic-gate PT_EXIT_READ(ptmp); 6287c478bd9Sstevel@tonic-gate DBG(("leaving ptmrsrv\n")); 6297c478bd9Sstevel@tonic-gate } 6307c478bd9Sstevel@tonic-gate 6317c478bd9Sstevel@tonic-gate 6327c478bd9Sstevel@tonic-gate /* 6337c478bd9Sstevel@tonic-gate * If there are messages on this queue that can be sent to 6347c478bd9Sstevel@tonic-gate * slave, send them via putnext(). Else, if queued messages 6357c478bd9Sstevel@tonic-gate * cannot be sent, leave them on this queue. If priority 6367c478bd9Sstevel@tonic-gate * messages on this queue, send them to slave no matter what. 6377c478bd9Sstevel@tonic-gate */ 6387c478bd9Sstevel@tonic-gate static void 6397c478bd9Sstevel@tonic-gate ptmwsrv(queue_t *qp) 6407c478bd9Sstevel@tonic-gate { 6417c478bd9Sstevel@tonic-gate struct pt_ttys *ptmp; 6427c478bd9Sstevel@tonic-gate mblk_t *mp; 6437c478bd9Sstevel@tonic-gate 6447c478bd9Sstevel@tonic-gate DBG(("entering ptmwsrv\n")); 6457c478bd9Sstevel@tonic-gate ASSERT(qp->q_ptr); 6467c478bd9Sstevel@tonic-gate 6477c478bd9Sstevel@tonic-gate ptmp = (struct pt_ttys *)qp->q_ptr; 6489acbbeafSnn35248 6499acbbeafSnn35248 if ((mp = getq(qp)) == NULL) { 6509acbbeafSnn35248 /* If there are no messages there's nothing to do. */ 6519acbbeafSnn35248 DBG(("leaving ptmwsrv (no messages)\n")); 6529acbbeafSnn35248 return; 6539acbbeafSnn35248 } 6549acbbeafSnn35248 6557c478bd9Sstevel@tonic-gate PT_ENTER_READ(ptmp); 6567c478bd9Sstevel@tonic-gate if ((ptmp->pt_state & PTLOCK) || (ptmp->pts_rdq == NULL)) { 6577c478bd9Sstevel@tonic-gate DBG(("in master write srv proc but no slave\n")); 6587c478bd9Sstevel@tonic-gate /* 6597c478bd9Sstevel@tonic-gate * Free messages on the write queue and send 6607c478bd9Sstevel@tonic-gate * NAK for any M_IOCTL type messages to wakeup 6617c478bd9Sstevel@tonic-gate * the user process waiting for ACK/NAK from 6627c478bd9Sstevel@tonic-gate * the ioctl invocation 6637c478bd9Sstevel@tonic-gate */ 6649acbbeafSnn35248 do { 6657c478bd9Sstevel@tonic-gate if (mp->b_datap->db_type == M_IOCTL) 6667c478bd9Sstevel@tonic-gate miocnak(qp, mp, 0, EINVAL); 6677c478bd9Sstevel@tonic-gate else 6687c478bd9Sstevel@tonic-gate freemsg(mp); 6699acbbeafSnn35248 } while ((mp = getq(qp)) != NULL); 6707c478bd9Sstevel@tonic-gate flushq(qp, FLUSHALL); 6717c478bd9Sstevel@tonic-gate 6727c478bd9Sstevel@tonic-gate mp = mexchange(NULL, NULL, 2, M_ERROR, -1); 6737c478bd9Sstevel@tonic-gate if (mp != NULL) { 6747c478bd9Sstevel@tonic-gate mp->b_rptr[0] = NOERROR; 6757c478bd9Sstevel@tonic-gate mp->b_rptr[1] = EINVAL; 6767c478bd9Sstevel@tonic-gate qreply(qp, mp); 6777c478bd9Sstevel@tonic-gate } 6787c478bd9Sstevel@tonic-gate PT_EXIT_READ(ptmp); 6797c478bd9Sstevel@tonic-gate return; 6807c478bd9Sstevel@tonic-gate } 6817c478bd9Sstevel@tonic-gate /* 6827c478bd9Sstevel@tonic-gate * while there are messages on this write queue... 6837c478bd9Sstevel@tonic-gate */ 6849acbbeafSnn35248 do { 6857c478bd9Sstevel@tonic-gate /* 6867c478bd9Sstevel@tonic-gate * if don't have control message and cannot put 6877c478bd9Sstevel@tonic-gate * msg. on slave's read queue, put it back on 6887c478bd9Sstevel@tonic-gate * this queue. 6897c478bd9Sstevel@tonic-gate */ 6907c478bd9Sstevel@tonic-gate if (mp->b_datap->db_type <= QPCTL && 6917c478bd9Sstevel@tonic-gate !bcanputnext(ptmp->pts_rdq, mp->b_band)) { 6927c478bd9Sstevel@tonic-gate DBG(("put msg. back on queue\n")); 6937c478bd9Sstevel@tonic-gate (void) putbq(qp, mp); 6947c478bd9Sstevel@tonic-gate break; 6957c478bd9Sstevel@tonic-gate } 6967c478bd9Sstevel@tonic-gate /* 6977c478bd9Sstevel@tonic-gate * else send the message up slave's stream 6987c478bd9Sstevel@tonic-gate */ 6997c478bd9Sstevel@tonic-gate DBG(("send message to slave\n")); 7007c478bd9Sstevel@tonic-gate putnext(ptmp->pts_rdq, mp); 7019acbbeafSnn35248 } while ((mp = getq(qp)) != NULL); 7027c478bd9Sstevel@tonic-gate DBG(("leaving ptmwsrv\n")); 7037c478bd9Sstevel@tonic-gate PT_EXIT_READ(ptmp); 7047c478bd9Sstevel@tonic-gate } 705