10Sstevel@tonic-gate /* 2*7656SSherry.Moore@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 30Sstevel@tonic-gate * Use is subject to license terms. 40Sstevel@tonic-gate */ 50Sstevel@tonic-gate 60Sstevel@tonic-gate /* 70Sstevel@tonic-gate * Copyright (c) 1983 Regents of the University of California. 80Sstevel@tonic-gate * All rights reserved. The Berkeley software License Agreement 90Sstevel@tonic-gate * specifies the terms and conditions for redistribution. 100Sstevel@tonic-gate */ 110Sstevel@tonic-gate 120Sstevel@tonic-gate /* 130Sstevel@tonic-gate * PTY - Stream "pseudo-tty" device. 140Sstevel@tonic-gate * This is the "slave" side. 150Sstevel@tonic-gate */ 160Sstevel@tonic-gate 170Sstevel@tonic-gate 180Sstevel@tonic-gate #include <sys/param.h> 190Sstevel@tonic-gate #include <sys/systm.h> 200Sstevel@tonic-gate #include <sys/filio.h> 210Sstevel@tonic-gate #include <sys/ioccom.h> 220Sstevel@tonic-gate #include <sys/termios.h> 230Sstevel@tonic-gate #include <sys/termio.h> 240Sstevel@tonic-gate #include <sys/ttold.h> 250Sstevel@tonic-gate #include <sys/stropts.h> 260Sstevel@tonic-gate #include <sys/stream.h> 270Sstevel@tonic-gate #include <sys/strsun.h> 280Sstevel@tonic-gate #include <sys/tty.h> 290Sstevel@tonic-gate #include <sys/user.h> 300Sstevel@tonic-gate #include <sys/conf.h> 310Sstevel@tonic-gate #include <sys/file.h> 320Sstevel@tonic-gate #include <sys/vnode.h> /* 1/0 on the vomit meter */ 330Sstevel@tonic-gate #include <sys/proc.h> 340Sstevel@tonic-gate #include <sys/uio.h> 350Sstevel@tonic-gate #include <sys/errno.h> 360Sstevel@tonic-gate #include <sys/strsubr.h> 370Sstevel@tonic-gate #include <sys/poll.h> 380Sstevel@tonic-gate #include <sys/sysmacros.h> 390Sstevel@tonic-gate #include <sys/debug.h> 400Sstevel@tonic-gate #include <sys/procset.h> 410Sstevel@tonic-gate #include <sys/cred.h> 420Sstevel@tonic-gate #include <sys/ptyvar.h> 430Sstevel@tonic-gate #include <sys/suntty.h> 440Sstevel@tonic-gate #include <sys/stat.h> 450Sstevel@tonic-gate #include <sys/policy.h> 460Sstevel@tonic-gate 470Sstevel@tonic-gate #include <sys/conf.h> 480Sstevel@tonic-gate #include <sys/ddi.h> 490Sstevel@tonic-gate #include <sys/sunddi.h> 500Sstevel@tonic-gate 510Sstevel@tonic-gate extern void gsignal(int pid, int sig); 520Sstevel@tonic-gate 530Sstevel@tonic-gate extern int npty; /* number of pseudo-ttys configured in */ 540Sstevel@tonic-gate extern struct pty *pty_softc; 550Sstevel@tonic-gate 560Sstevel@tonic-gate extern struct pollhead ptcph; /* poll head for ptcpoll() use */ 570Sstevel@tonic-gate 580Sstevel@tonic-gate #define IFLAGS (CS7|CREAD|PARENB) 590Sstevel@tonic-gate 600Sstevel@tonic-gate 610Sstevel@tonic-gate /* 620Sstevel@tonic-gate * Most of these should be "void", but the people who defined the "streams" 630Sstevel@tonic-gate * data structure for S5 didn't understand data types. 640Sstevel@tonic-gate */ 650Sstevel@tonic-gate 660Sstevel@tonic-gate /* 670Sstevel@tonic-gate * Slave side. This is a streams device. 680Sstevel@tonic-gate */ 690Sstevel@tonic-gate static int ptslopen(queue_t *, dev_t *, int flag, int, cred_t *); 700Sstevel@tonic-gate static int ptslclose(queue_t *, int, cred_t *); 710Sstevel@tonic-gate static int ptslrserv(queue_t *); 720Sstevel@tonic-gate 730Sstevel@tonic-gate /* 740Sstevel@tonic-gate * To save instructions, since STREAMS ignores the return value 750Sstevel@tonic-gate * from this function, it is defined as void here. Kind of icky, but... 760Sstevel@tonic-gate */ 770Sstevel@tonic-gate 780Sstevel@tonic-gate static void ptslwput(queue_t *q, mblk_t *mp); 790Sstevel@tonic-gate 800Sstevel@tonic-gate static struct module_info ptslm_info = { 810Sstevel@tonic-gate 0, 820Sstevel@tonic-gate "ptys", 830Sstevel@tonic-gate 0, 840Sstevel@tonic-gate INFPSZ, 850Sstevel@tonic-gate 2048, 860Sstevel@tonic-gate 200 870Sstevel@tonic-gate }; 880Sstevel@tonic-gate 890Sstevel@tonic-gate static struct qinit ptslrinit = { 900Sstevel@tonic-gate putq, 910Sstevel@tonic-gate ptslrserv, 920Sstevel@tonic-gate ptslopen, 930Sstevel@tonic-gate ptslclose, 940Sstevel@tonic-gate NULL, 950Sstevel@tonic-gate &ptslm_info, 960Sstevel@tonic-gate NULL 970Sstevel@tonic-gate }; 980Sstevel@tonic-gate 990Sstevel@tonic-gate static struct qinit ptslwinit = { 1000Sstevel@tonic-gate (int (*)())ptslwput, 1010Sstevel@tonic-gate NULL, 1020Sstevel@tonic-gate NULL, 1030Sstevel@tonic-gate NULL, 1040Sstevel@tonic-gate NULL, 1050Sstevel@tonic-gate &ptslm_info, 1060Sstevel@tonic-gate NULL 1070Sstevel@tonic-gate }; 1080Sstevel@tonic-gate 1090Sstevel@tonic-gate struct streamtab ptysinfo = { 1100Sstevel@tonic-gate &ptslrinit, 1110Sstevel@tonic-gate &ptslwinit, 1120Sstevel@tonic-gate NULL, 1130Sstevel@tonic-gate NULL 1140Sstevel@tonic-gate }; 1150Sstevel@tonic-gate 1160Sstevel@tonic-gate static void ptslreioctl(void *); 1170Sstevel@tonic-gate static void ptslioctl(struct pty *, queue_t *, mblk_t *); 1180Sstevel@tonic-gate static void pt_sendstop(struct pty *); 1190Sstevel@tonic-gate static void ptcpollwakeup(struct pty *, int); 1200Sstevel@tonic-gate 1210Sstevel@tonic-gate 1220Sstevel@tonic-gate static int ptsl_info(dev_info_t *, ddi_info_cmd_t, void *, void **); 1230Sstevel@tonic-gate static int ptsl_attach(dev_info_t *, ddi_attach_cmd_t); 1240Sstevel@tonic-gate static dev_info_t *ptsl_dip; /* for dev-to-dip conversions */ 1250Sstevel@tonic-gate 1260Sstevel@tonic-gate DDI_DEFINE_STREAM_OPS(ptsl_ops, nulldev, nulldev, 127*7656SSherry.Moore@Sun.COM ptsl_attach, nodev, nodev, ptsl_info, D_MP, &ptysinfo, 128*7656SSherry.Moore@Sun.COM ddi_quiesce_not_supported); 1290Sstevel@tonic-gate 1300Sstevel@tonic-gate #include <sys/types.h> 1310Sstevel@tonic-gate #include <sys/conf.h> 1320Sstevel@tonic-gate #include <sys/param.h> 1330Sstevel@tonic-gate #include <sys/systm.h> 1340Sstevel@tonic-gate #include <sys/errno.h> 1350Sstevel@tonic-gate #include <sys/modctl.h> 1360Sstevel@tonic-gate 1370Sstevel@tonic-gate char _depends_on[] = "drv/ptc"; 1380Sstevel@tonic-gate 1390Sstevel@tonic-gate /* 1400Sstevel@tonic-gate * Module linkage information for the kernel. 1410Sstevel@tonic-gate */ 1420Sstevel@tonic-gate 1430Sstevel@tonic-gate static struct modldrv modldrv = { 1440Sstevel@tonic-gate &mod_driverops, /* Type of module. This one is a pseudo driver */ 145*7656SSherry.Moore@Sun.COM "tty pseudo driver slave 'ptsl'", 1460Sstevel@tonic-gate &ptsl_ops, /* driver ops */ 1470Sstevel@tonic-gate }; 1480Sstevel@tonic-gate 1490Sstevel@tonic-gate static struct modlinkage modlinkage = { 1500Sstevel@tonic-gate MODREV_1, 1510Sstevel@tonic-gate &modldrv, 1520Sstevel@tonic-gate NULL 1530Sstevel@tonic-gate }; 1540Sstevel@tonic-gate 1550Sstevel@tonic-gate int 1560Sstevel@tonic-gate _init(void) 1570Sstevel@tonic-gate { 1580Sstevel@tonic-gate return (mod_install(&modlinkage)); 1590Sstevel@tonic-gate } 1600Sstevel@tonic-gate 1610Sstevel@tonic-gate int 1620Sstevel@tonic-gate _fini(void) 1630Sstevel@tonic-gate { 1640Sstevel@tonic-gate return (mod_remove(&modlinkage)); 1650Sstevel@tonic-gate } 1660Sstevel@tonic-gate 1670Sstevel@tonic-gate int 1680Sstevel@tonic-gate _info(struct modinfo *modinfop) 1690Sstevel@tonic-gate { 1700Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 1710Sstevel@tonic-gate } 1720Sstevel@tonic-gate 1730Sstevel@tonic-gate static char *tty_banks = PTY_BANKS; 1740Sstevel@tonic-gate static char *tty_digits = PTY_DIGITS; 1750Sstevel@tonic-gate 1760Sstevel@tonic-gate /* ARGSUSED */ 1770Sstevel@tonic-gate static int 1780Sstevel@tonic-gate ptsl_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 1790Sstevel@tonic-gate { 1800Sstevel@tonic-gate char name[8]; 1810Sstevel@tonic-gate int tty_num; 1820Sstevel@tonic-gate char *tty_digit = tty_digits; 1830Sstevel@tonic-gate char *tty_bank = tty_banks; 1840Sstevel@tonic-gate 1850Sstevel@tonic-gate for (tty_num = 0; tty_num < npty; tty_num++) { 1860Sstevel@tonic-gate (void) sprintf(name, "tty%c%c", *tty_bank, *tty_digit); 1870Sstevel@tonic-gate if (ddi_create_minor_node(devi, name, S_IFCHR, 188*7656SSherry.Moore@Sun.COM tty_num, DDI_PSEUDO, NULL) == DDI_FAILURE) { 1890Sstevel@tonic-gate ddi_remove_minor_node(devi, NULL); 1900Sstevel@tonic-gate return (-1); 1910Sstevel@tonic-gate } 1920Sstevel@tonic-gate if (*(++tty_digit) == '\0') { 1930Sstevel@tonic-gate tty_digit = tty_digits; 1940Sstevel@tonic-gate if (*(++tty_bank) == '\0') 1950Sstevel@tonic-gate break; 1960Sstevel@tonic-gate } 1970Sstevel@tonic-gate } 1980Sstevel@tonic-gate ptsl_dip = devi; 1990Sstevel@tonic-gate return (DDI_SUCCESS); 2000Sstevel@tonic-gate } 2010Sstevel@tonic-gate 2020Sstevel@tonic-gate /* ARGSUSED */ 2030Sstevel@tonic-gate static int 2040Sstevel@tonic-gate ptsl_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 2050Sstevel@tonic-gate void **result) 2060Sstevel@tonic-gate { 2070Sstevel@tonic-gate int error; 2080Sstevel@tonic-gate 2090Sstevel@tonic-gate switch (infocmd) { 2100Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 2110Sstevel@tonic-gate if (ptsl_dip == NULL) { 2120Sstevel@tonic-gate error = DDI_FAILURE; 2130Sstevel@tonic-gate } else { 2140Sstevel@tonic-gate *result = (void *)ptsl_dip; 2150Sstevel@tonic-gate error = DDI_SUCCESS; 2160Sstevel@tonic-gate } 2170Sstevel@tonic-gate break; 2180Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 2190Sstevel@tonic-gate *result = (void *)0; 2200Sstevel@tonic-gate error = DDI_SUCCESS; 2210Sstevel@tonic-gate break; 2220Sstevel@tonic-gate default: 2230Sstevel@tonic-gate error = DDI_FAILURE; 2240Sstevel@tonic-gate } 2250Sstevel@tonic-gate return (error); 2260Sstevel@tonic-gate } 2270Sstevel@tonic-gate 2280Sstevel@tonic-gate 2290Sstevel@tonic-gate /* 2300Sstevel@tonic-gate * Open the slave side of a pty. 2310Sstevel@tonic-gate */ 2320Sstevel@tonic-gate /*ARGSUSED*/ 2330Sstevel@tonic-gate static int 2340Sstevel@tonic-gate ptslopen(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *cred) 2350Sstevel@tonic-gate { 2360Sstevel@tonic-gate minor_t unit; 2370Sstevel@tonic-gate dev_t dev = *devp; 2380Sstevel@tonic-gate struct pty *pty; 2390Sstevel@tonic-gate 2400Sstevel@tonic-gate unit = getminor(dev); 2410Sstevel@tonic-gate if (unit >= npty) 2420Sstevel@tonic-gate return (ENXIO); 2430Sstevel@tonic-gate 2440Sstevel@tonic-gate pty = &pty_softc[unit]; 2450Sstevel@tonic-gate 2460Sstevel@tonic-gate mutex_enter(&pty->ptc_lock); 2470Sstevel@tonic-gate /* 2480Sstevel@tonic-gate * Block waiting for controller to open, unless this is a no-delay 2490Sstevel@tonic-gate * open. 2500Sstevel@tonic-gate */ 2510Sstevel@tonic-gate again: 2520Sstevel@tonic-gate if (pty->pt_ttycommon.t_writeq == NULL) { 2530Sstevel@tonic-gate pty->pt_ttycommon.t_iflag = 0; 2540Sstevel@tonic-gate pty->pt_ttycommon.t_cflag = (B38400 << IBSHIFT)|B38400|IFLAGS; 2550Sstevel@tonic-gate pty->pt_ttycommon.t_iocpending = NULL; 2560Sstevel@tonic-gate pty->pt_wbufcid = 0; 2570Sstevel@tonic-gate pty->pt_ttycommon.t_size.ws_row = 0; 2580Sstevel@tonic-gate pty->pt_ttycommon.t_size.ws_col = 0; 2590Sstevel@tonic-gate pty->pt_ttycommon.t_size.ws_xpixel = 0; 2600Sstevel@tonic-gate pty->pt_ttycommon.t_size.ws_ypixel = 0; 2610Sstevel@tonic-gate } else if ((pty->pt_ttycommon.t_flags & TS_XCLUDE) && 2620Sstevel@tonic-gate secpolicy_excl_open(cred) != 0) { 2630Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 2640Sstevel@tonic-gate return (EBUSY); 2650Sstevel@tonic-gate } 2660Sstevel@tonic-gate if (!(flag & (FNONBLOCK|FNDELAY)) && 2670Sstevel@tonic-gate !(pty->pt_ttycommon.t_cflag & CLOCAL)) { 2680Sstevel@tonic-gate if (!(pty->pt_flags & PF_CARR_ON)) { 2690Sstevel@tonic-gate pty->pt_flags |= PF_WOPEN; 2700Sstevel@tonic-gate if (!cv_wait_sig(&pty->pt_cv_flags, &pty->ptc_lock)) { 2710Sstevel@tonic-gate pty->pt_flags &= ~PF_WOPEN; 2720Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 2730Sstevel@tonic-gate return (EINTR); 2740Sstevel@tonic-gate } 2750Sstevel@tonic-gate goto again; 2760Sstevel@tonic-gate } 2770Sstevel@tonic-gate } 2780Sstevel@tonic-gate 2790Sstevel@tonic-gate /* 2800Sstevel@tonic-gate * queue has already been setup with a pointer to 2810Sstevel@tonic-gate * the stream head that is being referenced 2820Sstevel@tonic-gate */ 2830Sstevel@tonic-gate pty->pt_vnode = strq2vp(q); 2840Sstevel@tonic-gate VN_RELE(pty->pt_vnode); 2850Sstevel@tonic-gate pty->pt_sdev = dev; 2860Sstevel@tonic-gate q->q_ptr = WR(q)->q_ptr = pty; 2870Sstevel@tonic-gate pty->pt_flags &= ~PF_SLAVEGONE; 2880Sstevel@tonic-gate pty->pt_ttycommon.t_readq = pty->pt_ttycommon.t_writeq = NULL; 2890Sstevel@tonic-gate 2900Sstevel@tonic-gate /* 2910Sstevel@tonic-gate * Slave is ready to accept messages but master still can't send 2920Sstevel@tonic-gate * messages to the slave queue since it is not plumbed 2930Sstevel@tonic-gate * yet. So do qprocson() and finish slave initialization. 2940Sstevel@tonic-gate */ 2950Sstevel@tonic-gate 2960Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 2970Sstevel@tonic-gate 2980Sstevel@tonic-gate qprocson(q); 2990Sstevel@tonic-gate 3000Sstevel@tonic-gate /* 3010Sstevel@tonic-gate * Now it is safe to send messages to q, so wakeup master possibly 3020Sstevel@tonic-gate * waiting for slave queue to finish open. 3030Sstevel@tonic-gate */ 3040Sstevel@tonic-gate mutex_enter(&pty->ptc_lock); 3050Sstevel@tonic-gate pty->pt_ttycommon.t_readq = q; 3060Sstevel@tonic-gate pty->pt_ttycommon.t_writeq = WR(q); 3070Sstevel@tonic-gate /* tell master device that slave is ready for writing */ 3080Sstevel@tonic-gate if (pty->pt_flags & PF_CARR_ON) 3090Sstevel@tonic-gate cv_broadcast(&pty->pt_cv_readq); 3100Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 3110Sstevel@tonic-gate 3120Sstevel@tonic-gate return (0); 3130Sstevel@tonic-gate } 3140Sstevel@tonic-gate 3150Sstevel@tonic-gate static int 3160Sstevel@tonic-gate ptslclose(queue_t *q, int flag, cred_t *cred) 3170Sstevel@tonic-gate { 3180Sstevel@tonic-gate struct pty *pty; 3190Sstevel@tonic-gate bufcall_id_t pt_wbufcid = 0; 3200Sstevel@tonic-gate 3210Sstevel@tonic-gate #ifdef lint 3220Sstevel@tonic-gate flag = flag; 3230Sstevel@tonic-gate cred = cred; 3240Sstevel@tonic-gate #endif 3250Sstevel@tonic-gate 3260Sstevel@tonic-gate if ((pty = (struct pty *)q->q_ptr) == NULL) 3270Sstevel@tonic-gate return (ENODEV); /* already been closed once */ 3280Sstevel@tonic-gate 3290Sstevel@tonic-gate /* 3300Sstevel@tonic-gate * Prevent the queues from being uses by master device. 3310Sstevel@tonic-gate * This should be done before qprocsoff or writer may attempt 3320Sstevel@tonic-gate * to use the slave queue after qprocsoff removed it from the stream and 3330Sstevel@tonic-gate * before entering mutex_enter(). 3340Sstevel@tonic-gate */ 3350Sstevel@tonic-gate mutex_enter(&pty->ptc_lock); 3360Sstevel@tonic-gate pty->pt_ttycommon.t_readq = NULL; 3370Sstevel@tonic-gate pty->pt_ttycommon.t_writeq = NULL; 3380Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 3390Sstevel@tonic-gate 3400Sstevel@tonic-gate qprocsoff(q); 3410Sstevel@tonic-gate 3420Sstevel@tonic-gate mutex_enter(&pty->ptc_lock); 3430Sstevel@tonic-gate 3440Sstevel@tonic-gate while (pty->pt_flags & PF_IOCTL) { 3450Sstevel@tonic-gate pty->pt_flags |= PF_WAIT; 3460Sstevel@tonic-gate cv_wait(&pty->pt_cv_flags, &pty->ptc_lock); 3470Sstevel@tonic-gate } 3480Sstevel@tonic-gate 3490Sstevel@tonic-gate /* 3500Sstevel@tonic-gate * ptc_lock mutex is not dropped across 3510Sstevel@tonic-gate * the call to the routine ttycommon_close 3520Sstevel@tonic-gate */ 3530Sstevel@tonic-gate ttycommon_close(&pty->pt_ttycommon); 3540Sstevel@tonic-gate 3550Sstevel@tonic-gate /* 3560Sstevel@tonic-gate * Cancel outstanding "bufcall" request. 3570Sstevel@tonic-gate */ 3580Sstevel@tonic-gate if (pty->pt_wbufcid) { 3590Sstevel@tonic-gate pt_wbufcid = pty->pt_wbufcid; 3600Sstevel@tonic-gate pty->pt_wbufcid = 0; 3610Sstevel@tonic-gate } 3620Sstevel@tonic-gate 3630Sstevel@tonic-gate /* 3640Sstevel@tonic-gate * Clear out all the slave-side state. 3650Sstevel@tonic-gate */ 3660Sstevel@tonic-gate pty->pt_flags &= ~(PF_WOPEN|PF_STOPPED|PF_NOSTOP); 3670Sstevel@tonic-gate if (pty->pt_flags & PF_CARR_ON) { 3680Sstevel@tonic-gate pty->pt_flags |= PF_SLAVEGONE; /* let the controller know */ 3690Sstevel@tonic-gate ptcpollwakeup(pty, 0); /* wake up readers/selectors */ 3700Sstevel@tonic-gate ptcpollwakeup(pty, FWRITE); /* wake up writers/selectors */ 3710Sstevel@tonic-gate cv_broadcast(&pty->pt_cv_flags); 3720Sstevel@tonic-gate } 3730Sstevel@tonic-gate pty->pt_vnode = NULL; 3740Sstevel@tonic-gate pty->pt_sdev = 0; 3750Sstevel@tonic-gate q->q_ptr = WR(q)->q_ptr = NULL; 3760Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 3770Sstevel@tonic-gate 3780Sstevel@tonic-gate if (pt_wbufcid) 3790Sstevel@tonic-gate unbufcall(pt_wbufcid); 3800Sstevel@tonic-gate 3810Sstevel@tonic-gate return (0); 3820Sstevel@tonic-gate } 3830Sstevel@tonic-gate 3840Sstevel@tonic-gate /* 3850Sstevel@tonic-gate * Put procedure for write queue. 3860Sstevel@tonic-gate * Respond to M_STOP, M_START, M_IOCTL, and M_FLUSH messages here; 3870Sstevel@tonic-gate * queue up M_DATA messages for processing by the controller "read" 3880Sstevel@tonic-gate * routine; discard everything else. 3890Sstevel@tonic-gate */ 3900Sstevel@tonic-gate static void 3910Sstevel@tonic-gate ptslwput(queue_t *q, mblk_t *mp) 3920Sstevel@tonic-gate { 3930Sstevel@tonic-gate struct pty *pty; 3940Sstevel@tonic-gate mblk_t *bp; 3950Sstevel@tonic-gate 3960Sstevel@tonic-gate pty = (struct pty *)q->q_ptr; 3970Sstevel@tonic-gate 3980Sstevel@tonic-gate mutex_enter(&pty->ptc_lock); 3990Sstevel@tonic-gate 4000Sstevel@tonic-gate switch (mp->b_datap->db_type) { 4010Sstevel@tonic-gate 4020Sstevel@tonic-gate case M_STOP: 4030Sstevel@tonic-gate if (!(pty->pt_flags & PF_STOPPED)) { 4040Sstevel@tonic-gate pty->pt_flags |= PF_STOPPED; 4050Sstevel@tonic-gate pty->pt_send |= TIOCPKT_STOP; 4060Sstevel@tonic-gate ptcpollwakeup(pty, 0); 4070Sstevel@tonic-gate } 4080Sstevel@tonic-gate freemsg(mp); 4090Sstevel@tonic-gate break; 4100Sstevel@tonic-gate 4110Sstevel@tonic-gate case M_START: 4120Sstevel@tonic-gate if (pty->pt_flags & PF_STOPPED) { 4130Sstevel@tonic-gate pty->pt_flags &= ~PF_STOPPED; 4140Sstevel@tonic-gate pty->pt_send = TIOCPKT_START; 4150Sstevel@tonic-gate ptcpollwakeup(pty, 0); 4160Sstevel@tonic-gate } 4170Sstevel@tonic-gate ptcpollwakeup(pty, FREAD); /* permit controller to read */ 4180Sstevel@tonic-gate freemsg(mp); 4190Sstevel@tonic-gate break; 4200Sstevel@tonic-gate 4210Sstevel@tonic-gate case M_IOCTL: 4220Sstevel@tonic-gate ptslioctl(pty, q, mp); 4230Sstevel@tonic-gate break; 4240Sstevel@tonic-gate 4250Sstevel@tonic-gate case M_FLUSH: 4260Sstevel@tonic-gate if (*mp->b_rptr & FLUSHW) { 4270Sstevel@tonic-gate /* 4280Sstevel@tonic-gate * Set the "flush write" flag, so that we 4290Sstevel@tonic-gate * notify the controller if they're in packet 4300Sstevel@tonic-gate * or user control mode. 4310Sstevel@tonic-gate */ 4320Sstevel@tonic-gate if (!(pty->pt_send & TIOCPKT_FLUSHWRITE)) { 4330Sstevel@tonic-gate pty->pt_send |= TIOCPKT_FLUSHWRITE; 4340Sstevel@tonic-gate ptcpollwakeup(pty, 0); 4350Sstevel@tonic-gate } 4360Sstevel@tonic-gate /* 4370Sstevel@tonic-gate * Flush our write queue. 4380Sstevel@tonic-gate */ 4390Sstevel@tonic-gate flushq(q, FLUSHDATA); /* XXX doesn't flush M_DELAY */ 4400Sstevel@tonic-gate *mp->b_rptr &= ~FLUSHW; /* it has been flushed */ 4410Sstevel@tonic-gate } 4420Sstevel@tonic-gate if (*mp->b_rptr & FLUSHR) { 4430Sstevel@tonic-gate /* 4440Sstevel@tonic-gate * Set the "flush read" flag, so that we 4450Sstevel@tonic-gate * notify the controller if they're in packet 4460Sstevel@tonic-gate * mode. 4470Sstevel@tonic-gate */ 4480Sstevel@tonic-gate if (!(pty->pt_send & TIOCPKT_FLUSHREAD)) { 4490Sstevel@tonic-gate pty->pt_send |= TIOCPKT_FLUSHREAD; 4500Sstevel@tonic-gate ptcpollwakeup(pty, 0); 4510Sstevel@tonic-gate } 4520Sstevel@tonic-gate flushq(RD(q), FLUSHDATA); 4530Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 4540Sstevel@tonic-gate qreply(q, mp); /* give the read queues a crack at it */ 4550Sstevel@tonic-gate return; 4560Sstevel@tonic-gate } else 4570Sstevel@tonic-gate freemsg(mp); 4580Sstevel@tonic-gate break; 4590Sstevel@tonic-gate 4600Sstevel@tonic-gate case M_DATA: 4610Sstevel@tonic-gate /* 4620Sstevel@tonic-gate * Throw away any leading zero-length blocks, and queue it up 4630Sstevel@tonic-gate * for the controller to read. 4640Sstevel@tonic-gate */ 4650Sstevel@tonic-gate if (pty->pt_flags & PF_CARR_ON) { 4660Sstevel@tonic-gate bp = mp; 4670Sstevel@tonic-gate while ((bp->b_wptr - bp->b_rptr) == 0) { 4680Sstevel@tonic-gate mp = bp->b_cont; 4690Sstevel@tonic-gate freeb(bp); 4700Sstevel@tonic-gate if (mp == NULL) { 4710Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 4720Sstevel@tonic-gate return; /* damp squib of a message */ 4730Sstevel@tonic-gate } 4740Sstevel@tonic-gate bp = mp; 4750Sstevel@tonic-gate } 4760Sstevel@tonic-gate (void) putq(q, mp); 4770Sstevel@tonic-gate ptcpollwakeup(pty, FREAD); /* soup's on! */ 4780Sstevel@tonic-gate } else 4790Sstevel@tonic-gate freemsg(mp); /* nobody listening */ 4800Sstevel@tonic-gate break; 4810Sstevel@tonic-gate 4820Sstevel@tonic-gate case M_CTL: 4830Sstevel@tonic-gate if ((*(int *)mp->b_rptr) == MC_CANONQUERY) { 4840Sstevel@tonic-gate /* 4850Sstevel@tonic-gate * We're being asked whether we do canonicalization 4860Sstevel@tonic-gate * or not. Send a reply back up indicating whether 4870Sstevel@tonic-gate * we do or not. 4880Sstevel@tonic-gate */ 4890Sstevel@tonic-gate (void) putctl1(RD(q), M_CTL, 4900Sstevel@tonic-gate (pty->pt_flags & PF_REMOTE) ? 491*7656SSherry.Moore@Sun.COM MC_NOCANON : MC_DOCANON); 4920Sstevel@tonic-gate } 4930Sstevel@tonic-gate freemsg(mp); 4940Sstevel@tonic-gate break; 4950Sstevel@tonic-gate 4960Sstevel@tonic-gate default: 4970Sstevel@tonic-gate /* 4980Sstevel@tonic-gate * "No, I don't want a subscription to Chain Store Age, 4990Sstevel@tonic-gate * thank you anyway." 5000Sstevel@tonic-gate */ 5010Sstevel@tonic-gate freemsg(mp); 5020Sstevel@tonic-gate break; 5030Sstevel@tonic-gate } 5040Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 5050Sstevel@tonic-gate } 5060Sstevel@tonic-gate 5070Sstevel@tonic-gate /* 5080Sstevel@tonic-gate * Retry an "ioctl", now that "bufcall" claims we may be able to allocate 5090Sstevel@tonic-gate * the buffer we need. 5100Sstevel@tonic-gate */ 5110Sstevel@tonic-gate static void 5120Sstevel@tonic-gate ptslreioctl(void *arg) 5130Sstevel@tonic-gate { 5140Sstevel@tonic-gate struct pty *pty = arg; 5150Sstevel@tonic-gate queue_t *q; 5160Sstevel@tonic-gate mblk_t *mp; 5170Sstevel@tonic-gate 5180Sstevel@tonic-gate mutex_enter(&pty->ptc_lock); 5190Sstevel@tonic-gate /* 5200Sstevel@tonic-gate * The bufcall is no longer pending. 5210Sstevel@tonic-gate */ 5220Sstevel@tonic-gate if (pty->pt_wbufcid == 0) { 5230Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 5240Sstevel@tonic-gate return; 5250Sstevel@tonic-gate } 5260Sstevel@tonic-gate 5270Sstevel@tonic-gate pty->pt_wbufcid = 0; 5280Sstevel@tonic-gate if ((q = pty->pt_ttycommon.t_writeq) == NULL) { 5290Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 5300Sstevel@tonic-gate return; 5310Sstevel@tonic-gate } 5320Sstevel@tonic-gate if ((mp = pty->pt_ttycommon.t_iocpending) != NULL) { 5330Sstevel@tonic-gate /* It's not pending any more. */ 5340Sstevel@tonic-gate pty->pt_ttycommon.t_iocpending = NULL; 5350Sstevel@tonic-gate ptslioctl(pty, q, mp); 5360Sstevel@tonic-gate } 5370Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 5380Sstevel@tonic-gate } 5390Sstevel@tonic-gate 5400Sstevel@tonic-gate /* 5410Sstevel@tonic-gate * Process an "ioctl" message sent down to us. 5420Sstevel@tonic-gate * Drops pty's ptc_lock mutex and then reacquire 5430Sstevel@tonic-gate */ 5440Sstevel@tonic-gate static void 5450Sstevel@tonic-gate ptslioctl(struct pty *pty, queue_t *q, mblk_t *mp) 5460Sstevel@tonic-gate { 5470Sstevel@tonic-gate struct iocblk *iocp; 5480Sstevel@tonic-gate int cmd; 5490Sstevel@tonic-gate size_t datasize; 5500Sstevel@tonic-gate int error = 0; 5510Sstevel@tonic-gate 5520Sstevel@tonic-gate ASSERT(MUTEX_HELD(&pty->ptc_lock)); 5530Sstevel@tonic-gate 5540Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 5550Sstevel@tonic-gate cmd = iocp->ioc_cmd; 5560Sstevel@tonic-gate 5570Sstevel@tonic-gate switch (cmd) { 5580Sstevel@tonic-gate 5590Sstevel@tonic-gate case TIOCSTI: { 5600Sstevel@tonic-gate /* 5610Sstevel@tonic-gate * The permission checking has already been done at the stream 5620Sstevel@tonic-gate * head, since it has to be done in the context of the process 5630Sstevel@tonic-gate * doing the call. 5640Sstevel@tonic-gate */ 5650Sstevel@tonic-gate mblk_t *bp; 5660Sstevel@tonic-gate 5670Sstevel@tonic-gate error = miocpullup(mp, sizeof (char)); 5680Sstevel@tonic-gate if (error != 0) 5690Sstevel@tonic-gate goto out; 5700Sstevel@tonic-gate 5710Sstevel@tonic-gate /* 5720Sstevel@tonic-gate * Simulate typing of a character at the terminal. 5730Sstevel@tonic-gate */ 5740Sstevel@tonic-gate if ((bp = allocb(1, BPRI_MED)) != NULL) { 5750Sstevel@tonic-gate *bp->b_wptr++ = *mp->b_cont->b_rptr; 5760Sstevel@tonic-gate if (!(pty->pt_flags & PF_REMOTE)) { 5770Sstevel@tonic-gate if (!canput(pty->pt_ttycommon.t_readq)) { 5780Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 5790Sstevel@tonic-gate ttycommon_qfull(&pty->pt_ttycommon, q); 5800Sstevel@tonic-gate mutex_enter(&pty->ptc_lock); 5810Sstevel@tonic-gate freemsg(bp); 5820Sstevel@tonic-gate error = EAGAIN; 5830Sstevel@tonic-gate goto out; 5840Sstevel@tonic-gate } else 5850Sstevel@tonic-gate (void) putq( 5860Sstevel@tonic-gate pty->pt_ttycommon.t_readq, bp); 5870Sstevel@tonic-gate } else { 5880Sstevel@tonic-gate if (pty->pt_flags & PF_UCNTL) { 5890Sstevel@tonic-gate /* 5900Sstevel@tonic-gate * XXX - flow control; don't overflow 5910Sstevel@tonic-gate * this "queue". 5920Sstevel@tonic-gate */ 5930Sstevel@tonic-gate if (pty->pt_stuffqfirst != NULL) { 5940Sstevel@tonic-gate pty->pt_stuffqlast->b_next = bp; 5950Sstevel@tonic-gate bp->b_prev = pty->pt_stuffqlast; 5960Sstevel@tonic-gate } else { 5970Sstevel@tonic-gate pty->pt_stuffqfirst = bp; 5980Sstevel@tonic-gate bp->b_prev = NULL; 5990Sstevel@tonic-gate } 6000Sstevel@tonic-gate bp->b_next = NULL; 6010Sstevel@tonic-gate pty->pt_stuffqlast = bp; 6020Sstevel@tonic-gate pty->pt_stuffqlen++; 6030Sstevel@tonic-gate ptcpollwakeup(pty, 0); 6040Sstevel@tonic-gate } 6050Sstevel@tonic-gate } 6060Sstevel@tonic-gate } else { 6070Sstevel@tonic-gate error = EAGAIN; 6080Sstevel@tonic-gate goto out; 6090Sstevel@tonic-gate } 6100Sstevel@tonic-gate 6110Sstevel@tonic-gate /* 6120Sstevel@tonic-gate * Turn the ioctl message into an ioctl ACK message. 6130Sstevel@tonic-gate */ 6140Sstevel@tonic-gate iocp->ioc_count = 0; /* no data returned */ 6150Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK; 6160Sstevel@tonic-gate goto out; 6170Sstevel@tonic-gate } 6180Sstevel@tonic-gate 6190Sstevel@tonic-gate case TIOCSSIZE: { 6200Sstevel@tonic-gate tty_common_t *tc = &pty->pt_ttycommon; 6210Sstevel@tonic-gate struct ttysize *tp; 6220Sstevel@tonic-gate 6230Sstevel@tonic-gate error = miocpullup(mp, sizeof (struct ttysize)); 6240Sstevel@tonic-gate if (error != 0) 6250Sstevel@tonic-gate goto out; 6260Sstevel@tonic-gate 6270Sstevel@tonic-gate /* 6280Sstevel@tonic-gate * Set the window size, but don't send a SIGWINCH. 6290Sstevel@tonic-gate */ 6300Sstevel@tonic-gate tp = (struct ttysize *)mp->b_cont->b_rptr; 6310Sstevel@tonic-gate tc->t_size.ws_row = tp->ts_lines; 6320Sstevel@tonic-gate tc->t_size.ws_col = tp->ts_cols; 6330Sstevel@tonic-gate tc->t_size.ws_xpixel = 0; 6340Sstevel@tonic-gate tc->t_size.ws_ypixel = 0; 6350Sstevel@tonic-gate 6360Sstevel@tonic-gate /* 6370Sstevel@tonic-gate * Send an ACK back. 6380Sstevel@tonic-gate */ 6390Sstevel@tonic-gate iocp->ioc_count = 0; /* no data returned */ 6400Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK; 6410Sstevel@tonic-gate goto out; 6420Sstevel@tonic-gate } 6430Sstevel@tonic-gate 6440Sstevel@tonic-gate case TIOCGSIZE: { 6450Sstevel@tonic-gate tty_common_t *tc = &pty->pt_ttycommon; 6460Sstevel@tonic-gate mblk_t *datap; 6470Sstevel@tonic-gate struct ttysize *tp; 6480Sstevel@tonic-gate 6490Sstevel@tonic-gate if ((datap = allocb(sizeof (struct ttysize), 6500Sstevel@tonic-gate BPRI_HI)) == NULL) { 6510Sstevel@tonic-gate if (pty->pt_wbufcid) { 6520Sstevel@tonic-gate if (pty->pt_ttycommon.t_iocpending) 6530Sstevel@tonic-gate freemsg(pty->pt_ttycommon.t_iocpending); 6540Sstevel@tonic-gate pty->pt_ttycommon.t_iocpending = mp; 6550Sstevel@tonic-gate return; 6560Sstevel@tonic-gate } 6570Sstevel@tonic-gate pty->pt_wbufcid = bufcall(sizeof (struct ttysize), 6580Sstevel@tonic-gate BPRI_HI, ptslreioctl, pty); 6590Sstevel@tonic-gate if (pty->pt_wbufcid == 0) { 6600Sstevel@tonic-gate error = ENOMEM; 6610Sstevel@tonic-gate goto out; 6620Sstevel@tonic-gate } 6630Sstevel@tonic-gate pty->pt_ttycommon.t_iocpending = mp; 6640Sstevel@tonic-gate return; 6650Sstevel@tonic-gate } 6660Sstevel@tonic-gate /* 6670Sstevel@tonic-gate * Return the current size. 6680Sstevel@tonic-gate */ 6690Sstevel@tonic-gate tp = (struct ttysize *)datap->b_wptr; 6700Sstevel@tonic-gate tp->ts_lines = tc->t_size.ws_row; 6710Sstevel@tonic-gate tp->ts_cols = tc->t_size.ws_col; 6720Sstevel@tonic-gate datap->b_wptr += sizeof (struct ttysize); 6730Sstevel@tonic-gate iocp->ioc_count = sizeof (struct ttysize); 6740Sstevel@tonic-gate 6750Sstevel@tonic-gate if (mp->b_cont != NULL) 6760Sstevel@tonic-gate freemsg(mp->b_cont); 6770Sstevel@tonic-gate mp->b_cont = datap; 6780Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK; 6790Sstevel@tonic-gate goto out; 6800Sstevel@tonic-gate } 6810Sstevel@tonic-gate 6820Sstevel@tonic-gate /* 6830Sstevel@tonic-gate * Imported from ttycommon_ioctl routine 6840Sstevel@tonic-gate */ 6850Sstevel@tonic-gate 6860Sstevel@tonic-gate case TCSETSF: { 6870Sstevel@tonic-gate tty_common_t *tc = &pty->pt_ttycommon; 6880Sstevel@tonic-gate struct termios *cb; 6890Sstevel@tonic-gate 6900Sstevel@tonic-gate error = miocpullup(mp, sizeof (struct termios)); 6910Sstevel@tonic-gate if (error != 0) 6920Sstevel@tonic-gate goto out; 6930Sstevel@tonic-gate 6940Sstevel@tonic-gate cb = (struct termios *)mp->b_cont->b_rptr; 6950Sstevel@tonic-gate 6960Sstevel@tonic-gate flushq(RD(q), FLUSHDATA); 6970Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 6980Sstevel@tonic-gate (void) putnextctl1(RD(q), M_FLUSH, FLUSHR); 6990Sstevel@tonic-gate mutex_enter(&pty->ptc_lock); 7000Sstevel@tonic-gate mutex_enter(&tc->t_excl); 7010Sstevel@tonic-gate tc->t_iflag = cb->c_iflag; 7020Sstevel@tonic-gate tc->t_cflag = cb->c_cflag; 7030Sstevel@tonic-gate tc->t_stopc = cb->c_cc[VSTOP]; 7040Sstevel@tonic-gate tc->t_startc = cb->c_cc[VSTART]; 7050Sstevel@tonic-gate mutex_exit(&tc->t_excl); 7060Sstevel@tonic-gate 7070Sstevel@tonic-gate /* 7080Sstevel@tonic-gate * Turn the ioctl message into an ioctl ACK message. 7090Sstevel@tonic-gate */ 7100Sstevel@tonic-gate iocp->ioc_count = 0; /* no data returned */ 7110Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK; 7120Sstevel@tonic-gate goto ioctldone; 7130Sstevel@tonic-gate } 7140Sstevel@tonic-gate 7150Sstevel@tonic-gate case TCSETAF: { 7160Sstevel@tonic-gate tty_common_t *tc = &pty->pt_ttycommon; 7170Sstevel@tonic-gate struct termios *cb; 7180Sstevel@tonic-gate 7190Sstevel@tonic-gate error = miocpullup(mp, sizeof (struct termios)); 7200Sstevel@tonic-gate if (error != 0) 7210Sstevel@tonic-gate goto out; 7220Sstevel@tonic-gate 7230Sstevel@tonic-gate cb = (struct termios *)mp->b_cont->b_rptr; 7240Sstevel@tonic-gate 7250Sstevel@tonic-gate flushq(RD(q), FLUSHDATA); 7260Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 7270Sstevel@tonic-gate (void) putnextctl1(RD(q), M_FLUSH, FLUSHR); 7280Sstevel@tonic-gate mutex_enter(&pty->ptc_lock); 7290Sstevel@tonic-gate mutex_enter(&tc->t_excl); 7300Sstevel@tonic-gate tc->t_iflag = (tc->t_iflag & 0xffff0000 | cb->c_iflag); 7310Sstevel@tonic-gate tc->t_cflag = (tc->t_cflag & 0xffff0000 | cb->c_cflag); 7320Sstevel@tonic-gate mutex_exit(&tc->t_excl); 7330Sstevel@tonic-gate 7340Sstevel@tonic-gate /* 7350Sstevel@tonic-gate * Turn the ioctl message into an ioctl ACK message. 7360Sstevel@tonic-gate */ 7370Sstevel@tonic-gate iocp->ioc_count = 0; /* no data returned */ 7380Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK; 7390Sstevel@tonic-gate goto ioctldone; 7400Sstevel@tonic-gate } 7410Sstevel@tonic-gate 7420Sstevel@tonic-gate case TIOCSWINSZ: { 7430Sstevel@tonic-gate tty_common_t *tc = &pty->pt_ttycommon; 7440Sstevel@tonic-gate struct winsize *ws; 7450Sstevel@tonic-gate 7460Sstevel@tonic-gate error = miocpullup(mp, sizeof (struct winsize)); 7470Sstevel@tonic-gate if (error != 0) 7480Sstevel@tonic-gate goto out; 7490Sstevel@tonic-gate 7500Sstevel@tonic-gate ws = (struct winsize *)mp->b_cont->b_rptr; 7510Sstevel@tonic-gate /* 7520Sstevel@tonic-gate * If the window size changed, send a SIGWINCH. 7530Sstevel@tonic-gate */ 7540Sstevel@tonic-gate mutex_enter(&tc->t_excl); 7550Sstevel@tonic-gate if (bcmp(&tc->t_size, ws, sizeof (struct winsize))) { 7560Sstevel@tonic-gate tc->t_size = *ws; 7570Sstevel@tonic-gate mutex_exit(&tc->t_excl); 7580Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 7590Sstevel@tonic-gate (void) putnextctl1(RD(q), M_PCSIG, SIGWINCH); 7600Sstevel@tonic-gate mutex_enter(&pty->ptc_lock); 7610Sstevel@tonic-gate } else 7620Sstevel@tonic-gate mutex_exit(&tc->t_excl); 7630Sstevel@tonic-gate 7640Sstevel@tonic-gate /* 7650Sstevel@tonic-gate * Turn the ioctl message into an ioctl ACK message. 7660Sstevel@tonic-gate */ 7670Sstevel@tonic-gate iocp->ioc_count = 0; /* no data returned */ 7680Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK; 7690Sstevel@tonic-gate goto ioctldone; 7700Sstevel@tonic-gate } 7710Sstevel@tonic-gate 7720Sstevel@tonic-gate /* 7730Sstevel@tonic-gate * If they were just trying to drain output, that's OK. 7740Sstevel@tonic-gate * If they are actually trying to send a break it's an error. 7750Sstevel@tonic-gate */ 7760Sstevel@tonic-gate case TCSBRK: 7770Sstevel@tonic-gate error = miocpullup(mp, sizeof (int)); 7780Sstevel@tonic-gate if (error != 0) 7790Sstevel@tonic-gate goto out; 7800Sstevel@tonic-gate 7810Sstevel@tonic-gate if (*(int *)mp->b_cont->b_rptr != 0) { 7820Sstevel@tonic-gate /* 7830Sstevel@tonic-gate * Turn the ioctl message into an ioctl ACK message. 7840Sstevel@tonic-gate */ 7850Sstevel@tonic-gate iocp->ioc_count = 0; /* no data returned */ 7860Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK; 7870Sstevel@tonic-gate } else { 7880Sstevel@tonic-gate error = ENOTTY; 7890Sstevel@tonic-gate } 7900Sstevel@tonic-gate goto out; 7910Sstevel@tonic-gate } 7920Sstevel@tonic-gate 7930Sstevel@tonic-gate /* 7940Sstevel@tonic-gate * The only way in which "ttycommon_ioctl" can fail is if the "ioctl" 7950Sstevel@tonic-gate * requires a response containing data to be returned to the user, 7960Sstevel@tonic-gate * and no mblk could be allocated for the data. 7970Sstevel@tonic-gate * No such "ioctl" alters our state. Thus, we always go ahead and 7980Sstevel@tonic-gate * do any state-changes the "ioctl" calls for. If we couldn't allocate 7990Sstevel@tonic-gate * the data, "ttycommon_ioctl" has stashed the "ioctl" away safely, so 8000Sstevel@tonic-gate * we just call "bufcall" to request that we be called back when we 8010Sstevel@tonic-gate * stand a better chance of allocating the data. 8020Sstevel@tonic-gate */ 8030Sstevel@tonic-gate if ((datasize = 8040Sstevel@tonic-gate ttycommon_ioctl(&pty->pt_ttycommon, q, mp, &error)) != 0) { 8050Sstevel@tonic-gate if (pty->pt_wbufcid) { 8060Sstevel@tonic-gate if (pty->pt_ttycommon.t_iocpending) 8070Sstevel@tonic-gate freemsg(pty->pt_ttycommon.t_iocpending); 8080Sstevel@tonic-gate pty->pt_ttycommon.t_iocpending = mp; 8090Sstevel@tonic-gate return; 8100Sstevel@tonic-gate } 8110Sstevel@tonic-gate pty->pt_wbufcid = bufcall(datasize, BPRI_HI, ptslreioctl, pty); 8120Sstevel@tonic-gate if (pty->pt_wbufcid == 0) { 8130Sstevel@tonic-gate error = ENOMEM; 8140Sstevel@tonic-gate goto out; 8150Sstevel@tonic-gate } 8160Sstevel@tonic-gate pty->pt_ttycommon.t_iocpending = mp; 8170Sstevel@tonic-gate return; 8180Sstevel@tonic-gate } 8190Sstevel@tonic-gate 8200Sstevel@tonic-gate ioctldone: 8210Sstevel@tonic-gate if (error == 0) { 8220Sstevel@tonic-gate /* 8230Sstevel@tonic-gate * "ttycommon_ioctl" did most of the work; we just use the 8240Sstevel@tonic-gate * data it set up. 8250Sstevel@tonic-gate */ 8260Sstevel@tonic-gate switch (cmd) { 8270Sstevel@tonic-gate 8280Sstevel@tonic-gate case TCSETSF: 8290Sstevel@tonic-gate case TCSETAF: 8300Sstevel@tonic-gate /* 8310Sstevel@tonic-gate * Set the "flush read" flag, so that we 8320Sstevel@tonic-gate * notify the controller if they're in packet 8330Sstevel@tonic-gate * mode. 8340Sstevel@tonic-gate */ 8350Sstevel@tonic-gate if (!(pty->pt_send & TIOCPKT_FLUSHREAD)) { 8360Sstevel@tonic-gate pty->pt_send |= TIOCPKT_FLUSHREAD; 8370Sstevel@tonic-gate ptcpollwakeup(pty, 0); 8380Sstevel@tonic-gate } 8390Sstevel@tonic-gate /*FALLTHROUGH*/ 8400Sstevel@tonic-gate 8410Sstevel@tonic-gate case TCSETSW: 8420Sstevel@tonic-gate case TCSETAW: 8430Sstevel@tonic-gate cmd = TIOCSETP; /* map backwards to old codes */ 8440Sstevel@tonic-gate pt_sendstop(pty); 8450Sstevel@tonic-gate break; 8460Sstevel@tonic-gate 8470Sstevel@tonic-gate case TCSETS: 8480Sstevel@tonic-gate case TCSETA: 8490Sstevel@tonic-gate cmd = TIOCSETN; /* map backwards to old codes */ 8500Sstevel@tonic-gate pt_sendstop(pty); 8510Sstevel@tonic-gate break; 8520Sstevel@tonic-gate } 8530Sstevel@tonic-gate } 8540Sstevel@tonic-gate 8550Sstevel@tonic-gate if (pty->pt_flags & PF_43UCNTL) { 8560Sstevel@tonic-gate if (error < 0) { 8570Sstevel@tonic-gate if ((cmd & ~0xff) == _IO('u', 0)) { 8580Sstevel@tonic-gate if (cmd & 0xff) { 8590Sstevel@tonic-gate pty->pt_ucntl = (uchar_t)cmd & 0xff; 8600Sstevel@tonic-gate ptcpollwakeup(pty, FREAD); 8610Sstevel@tonic-gate } 8620Sstevel@tonic-gate error = 0; /* XXX */ 8630Sstevel@tonic-gate goto out; 8640Sstevel@tonic-gate } 8650Sstevel@tonic-gate error = ENOTTY; 8660Sstevel@tonic-gate } 8670Sstevel@tonic-gate } else { 8680Sstevel@tonic-gate if ((pty->pt_flags & PF_UCNTL) && 8690Sstevel@tonic-gate (cmd & (IOC_INOUT | 0xff00)) == (IOC_IN|('t'<<8)) && 8700Sstevel@tonic-gate (cmd & 0xff)) { 8710Sstevel@tonic-gate pty->pt_ucntl = (uchar_t)cmd & 0xff; 8720Sstevel@tonic-gate ptcpollwakeup(pty, FREAD); 8730Sstevel@tonic-gate goto out; 8740Sstevel@tonic-gate } 8750Sstevel@tonic-gate if (error < 0) 8760Sstevel@tonic-gate error = ENOTTY; 8770Sstevel@tonic-gate } 8780Sstevel@tonic-gate 8790Sstevel@tonic-gate out: 8800Sstevel@tonic-gate if (error != 0) { 8810Sstevel@tonic-gate ((struct iocblk *)mp->b_rptr)->ioc_error = error; 8820Sstevel@tonic-gate mp->b_datap->db_type = M_IOCNAK; 8830Sstevel@tonic-gate } 8840Sstevel@tonic-gate 8850Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 8860Sstevel@tonic-gate qreply(q, mp); 8870Sstevel@tonic-gate mutex_enter(&pty->ptc_lock); 8880Sstevel@tonic-gate } 8890Sstevel@tonic-gate 8900Sstevel@tonic-gate /* 8910Sstevel@tonic-gate * Service routine for read queue. 8920Sstevel@tonic-gate * Just wakes the controller side up so it can write some more data 8930Sstevel@tonic-gate * to that queue. 8940Sstevel@tonic-gate */ 8950Sstevel@tonic-gate static int 8960Sstevel@tonic-gate ptslrserv(queue_t *q) 8970Sstevel@tonic-gate { 8980Sstevel@tonic-gate struct pty *pty = (struct pty *)q->q_ptr; 8990Sstevel@tonic-gate mblk_t *mp; 9000Sstevel@tonic-gate mblk_t *head = NULL, *tail = NULL; 9010Sstevel@tonic-gate /* 9020Sstevel@tonic-gate * Build up the link list of messages, then drop 9030Sstevel@tonic-gate * drop the lock and do putnext() 9040Sstevel@tonic-gate */ 9050Sstevel@tonic-gate mutex_enter(&pty->ptc_lock); 9060Sstevel@tonic-gate 9070Sstevel@tonic-gate while ((mp = getq(q)) != NULL) { 9080Sstevel@tonic-gate if ((mp->b_datap->db_type < QPCTL) && !canputnext(q)) { 9090Sstevel@tonic-gate (void) putbq(q, mp); 9100Sstevel@tonic-gate break; 9110Sstevel@tonic-gate } 9120Sstevel@tonic-gate if (!head) { 9130Sstevel@tonic-gate head = mp; 9140Sstevel@tonic-gate tail = mp; 9150Sstevel@tonic-gate } else { 9160Sstevel@tonic-gate tail->b_next = mp; 9170Sstevel@tonic-gate tail = mp; 9180Sstevel@tonic-gate } 9190Sstevel@tonic-gate } 9200Sstevel@tonic-gate 9210Sstevel@tonic-gate if (q->q_count <= q->q_lowat) 9220Sstevel@tonic-gate ptcpollwakeup((struct pty *)q->q_ptr, FWRITE); 9230Sstevel@tonic-gate 9240Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 9250Sstevel@tonic-gate 9260Sstevel@tonic-gate while (head) { 9270Sstevel@tonic-gate mp = head; 9280Sstevel@tonic-gate head = mp->b_next; 9290Sstevel@tonic-gate mp->b_next = NULL; 9300Sstevel@tonic-gate putnext(q, mp); 9310Sstevel@tonic-gate } 9320Sstevel@tonic-gate 9330Sstevel@tonic-gate return (0); 9340Sstevel@tonic-gate } 9350Sstevel@tonic-gate 9360Sstevel@tonic-gate static void 9370Sstevel@tonic-gate pt_sendstop(struct pty *pty) 9380Sstevel@tonic-gate { 9390Sstevel@tonic-gate int stop; 9400Sstevel@tonic-gate 9410Sstevel@tonic-gate ASSERT(MUTEX_HELD(&pty->ptc_lock)); 9420Sstevel@tonic-gate 9430Sstevel@tonic-gate if ((pty->pt_ttycommon.t_cflag&CBAUD) == 0) { 9440Sstevel@tonic-gate if (pty->pt_flags & PF_CARR_ON) { 9450Sstevel@tonic-gate /* 9460Sstevel@tonic-gate * Let the controller know, then wake up 9470Sstevel@tonic-gate * readers/selectors and writers/selectors. 9480Sstevel@tonic-gate */ 9490Sstevel@tonic-gate pty->pt_flags |= PF_SLAVEGONE; 9500Sstevel@tonic-gate ptcpollwakeup(pty, 0); 9510Sstevel@tonic-gate ptcpollwakeup(pty, FWRITE); 9520Sstevel@tonic-gate } 9530Sstevel@tonic-gate } 9540Sstevel@tonic-gate 9550Sstevel@tonic-gate stop = (pty->pt_ttycommon.t_iflag & IXON) && 9560Sstevel@tonic-gate pty->pt_ttycommon.t_stopc == CTRL('s') && 9570Sstevel@tonic-gate pty->pt_ttycommon.t_startc == CTRL('q'); 9580Sstevel@tonic-gate 9590Sstevel@tonic-gate if (pty->pt_flags & PF_NOSTOP) { 9600Sstevel@tonic-gate if (stop) { 9610Sstevel@tonic-gate pty->pt_send &= ~TIOCPKT_NOSTOP; 9620Sstevel@tonic-gate pty->pt_send |= TIOCPKT_DOSTOP; 9630Sstevel@tonic-gate pty->pt_flags &= ~PF_NOSTOP; 9640Sstevel@tonic-gate ptcpollwakeup(pty, 0); 9650Sstevel@tonic-gate } 9660Sstevel@tonic-gate } else { 9670Sstevel@tonic-gate if (!stop) { 9680Sstevel@tonic-gate pty->pt_send &= ~TIOCPKT_DOSTOP; 9690Sstevel@tonic-gate pty->pt_send |= TIOCPKT_NOSTOP; 9700Sstevel@tonic-gate pty->pt_flags |= PF_NOSTOP; 9710Sstevel@tonic-gate ptcpollwakeup(pty, 0); 9720Sstevel@tonic-gate } 9730Sstevel@tonic-gate } 9740Sstevel@tonic-gate } 9750Sstevel@tonic-gate 9760Sstevel@tonic-gate /* 9770Sstevel@tonic-gate * Wake up controller side. "flag" is 0 if a special packet or 9780Sstevel@tonic-gate * user control mode message has been queued up (this data is readable, 9790Sstevel@tonic-gate * so we also treat it as a regular data event; should we send SIGIO, 9800Sstevel@tonic-gate * though?), FREAD if regular data has been queued up, or FWRITE if 9810Sstevel@tonic-gate * the slave's read queue has drained sufficiently to allow writing. 9820Sstevel@tonic-gate */ 9830Sstevel@tonic-gate static void 9840Sstevel@tonic-gate ptcpollwakeup(struct pty *pty, int flag) 9850Sstevel@tonic-gate { 9860Sstevel@tonic-gate ASSERT(MUTEX_HELD(&pty->ptc_lock)); 9870Sstevel@tonic-gate 9880Sstevel@tonic-gate if (flag == 0) { 9890Sstevel@tonic-gate /* 9900Sstevel@tonic-gate * "Exceptional condition" occurred. This means that 9910Sstevel@tonic-gate * a "read" is now possible, so do a "read" wakeup. 9920Sstevel@tonic-gate */ 9930Sstevel@tonic-gate flag = FREAD; 9940Sstevel@tonic-gate pollwakeup(&ptcph, POLLIN | POLLRDBAND); 9950Sstevel@tonic-gate if (pty->pt_flags & PF_ASYNC) 9960Sstevel@tonic-gate gsignal(pty->pt_pgrp, SIGURG); 9970Sstevel@tonic-gate } 9980Sstevel@tonic-gate if (flag & FREAD) { 9990Sstevel@tonic-gate /* 10000Sstevel@tonic-gate * Wake up the parent process as there is regular 10010Sstevel@tonic-gate * data to read from slave's write queue 10020Sstevel@tonic-gate */ 10030Sstevel@tonic-gate pollwakeup(&ptcph, POLLIN | POLLRDNORM); 10040Sstevel@tonic-gate cv_broadcast(&pty->pt_cv_writeq); 10050Sstevel@tonic-gate if (pty->pt_flags & PF_ASYNC) 10060Sstevel@tonic-gate gsignal(pty->pt_pgrp, SIGIO); 10070Sstevel@tonic-gate } 10080Sstevel@tonic-gate if (flag & FWRITE) { 10090Sstevel@tonic-gate /* 10100Sstevel@tonic-gate * Wake up the parent process to write 10110Sstevel@tonic-gate * data into slave's read queue as the 10120Sstevel@tonic-gate * read queue has drained enough 10130Sstevel@tonic-gate */ 10140Sstevel@tonic-gate pollwakeup(&ptcph, POLLOUT | POLLWRNORM); 10150Sstevel@tonic-gate cv_broadcast(&pty->pt_cv_readq); 10160Sstevel@tonic-gate if (pty->pt_flags & PF_ASYNC) 10170Sstevel@tonic-gate gsignal(pty->pt_pgrp, SIGIO); 10180Sstevel@tonic-gate } 10190Sstevel@tonic-gate } 1020