1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 /*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T     */
  26 /*        All Rights Reserved   */
  27 
  28 /*
  29  * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
  30  */
  31 
  32 /*
  33  * Pseudo Terminal Slave Driver.
  34  *
  35  * The pseudo-tty subsystem simulates a terminal connection, where the master
  36  * side represents the terminal and the slave represents the user process's
  37  * special device end point. The master device is set up as a cloned device
  38  * where its major device number is the major for the clone device and its minor
  39  * device number is the major for the ptm driver. There are no nodes in the file
  40  * system for master devices. The master pseudo driver is opened using the
  41  * open(2) system call with /dev/ptmx as the device parameter.  The clone open
  42  * finds the next available minor device for the ptm major device.
  43  *
  44  * A master device is available only if it and its corresponding slave device
  45  * are not already open. When the master device is opened, the corresponding
  46  * slave device is automatically locked out. Only one open is allowed on a
  47  * master device.  Multiple opens are allowed on the slave device.  After both
  48  * the master and slave have been opened, the user has two file descriptors
  49  * which are the end points of a full duplex connection composed of two streams
  50  * which are automatically connected at the master and slave drivers. The user
  51  * may then push modules onto either side of the stream pair.
  52  *
  53  * The master and slave drivers pass all messages to their adjacent queues.
  54  * Only the M_FLUSH needs some processing.  Because the read queue of one side
  55  * is connected to the write queue of the other, the FLUSHR flag is changed to
  56  * the FLUSHW flag and vice versa. When the master device is closed an M_HANGUP
  57  * message is sent to the slave device which will render the device
  58  * unusable. The process on the slave side gets the EIO when attempting to write
  59  * on that stream but it will be able to read any data remaining on the stream
  60  * head read queue.  When all the data has been read, read() returns 0
  61  * indicating that the stream can no longer be used.  On the last close of the
  62  * slave device, a 0-length message is sent to the master device. When the
  63  * application on the master side issues a read() or getmsg() and 0 is returned,
  64  * the user of the master device decides whether to issue a close() that
  65  * dismantles the pseudo-terminal subsystem. If the master device is not closed,
  66  * the pseudo-tty subsystem will be available to another user to open the slave
  67  * device.
  68  *
  69  * Synchronization:
  70  *
  71  *   All global data synchronization between ptm/pts is done via global
  72  *   ptms_lock mutex which is initialized at system boot time from
  73  *   ptms_initspace (called from space.c).
  74  *
  75  *   Individual fields of pt_ttys structure (except ptm_rdq, pts_rdq and
  76  *   pt_nullmsg) are protected by pt_ttys.pt_lock mutex.
  77  *
  78  *   PT_ENTER_READ/PT_ENTER_WRITE are reference counter based read-write locks
  79  *   which allow reader locks to be reacquired by the same thread (usual
  80  *   reader/writer locks can't be used for that purpose since it is illegal for
  81  *   a thread to acquire a lock it already holds, even as a reader). The sole
  82  *   purpose of these macros is to guarantee that the peer queue will not
  83  *   disappear (due to closing peer) while it is used. It is safe to use
  84  *   PT_ENTER_READ/PT_EXIT_READ brackets across calls like putq/putnext (since
  85  *   they are not real locks but reference counts).
  86  *
  87  *   PT_ENTER_WRITE/PT_EXIT_WRITE brackets are used ONLY in master/slave
  88  *   open/close paths to modify ptm_rdq and pts_rdq fields. These fields should
  89  *   be set to appropriate queues *after* qprocson() is called during open (to
  90  *   prevent peer from accessing the queue with incomplete plumbing) and set to
  91  *   NULL before qprocsoff() is called during close.
  92  *
  93  *   The pt_nullmsg field is only used in open/close routines and it is also
  94  *   protected by PT_ENTER_WRITE/PT_EXIT_WRITE brackets to avoid extra mutex
  95  *   holds.
  96  *
  97  * Lock Ordering:
  98  *
  99  *   If both ptms_lock and per-pty lock should be held, ptms_lock should always
 100  *   be entered first, followed by per-pty lock.
 101  *
 102  * See ptms.h, ptm.c and ptms_conf.c fore more information.
 103  *
 104  */
 105 
 106 #include <sys/types.h>
 107 #include <sys/param.h>
 108 #include <sys/sysmacros.h>
 109 #include <sys/stream.h>
 110 #include <sys/stropts.h>
 111 #include <sys/strsubr.h>
 112 #include <sys/stat.h>
 113 #include <sys/errno.h>
 114 #include <sys/debug.h>
 115 #include <sys/cmn_err.h>
 116 #include <sys/ptms.h>
 117 #include <sys/systm.h>
 118 #include <sys/modctl.h>
 119 #include <sys/conf.h>
 120 #include <sys/ddi.h>
 121 #include <sys/sunddi.h>
 122 #include <sys/cred.h>
 123 #include <sys/zone.h>
 124 
 125 #ifdef DEBUG
 126 int pts_debug = 0;
 127 #define DBG(a)   if (pts_debug) cmn_err(CE_NOTE, a)
 128 #else
 129 #define DBG(a)
 130 #endif
 131 
 132 static int ptsopen(queue_t *, dev_t *, int, int, cred_t *);
 133 static int ptsclose(queue_t *, int, cred_t *);
 134 static int ptswput(queue_t *, mblk_t *);
 135 static int ptsrsrv(queue_t *);
 136 static int ptswsrv(queue_t *);
 137 
 138 /*
 139  * Slave Stream Pseudo Terminal Module: stream data structure definitions
 140  */
 141 static struct module_info pts_info = {
 142         0xface,
 143         "pts",
 144         0,
 145         _TTY_BUFSIZ,
 146         _TTY_BUFSIZ,
 147         128
 148 };
 149 
 150 static struct qinit ptsrint = {
 151         NULL,
 152         ptsrsrv,
 153         ptsopen,
 154         ptsclose,
 155         NULL,
 156         &pts_info,
 157         NULL
 158 };
 159 
 160 static struct qinit ptswint = {
 161         ptswput,
 162         ptswsrv,
 163         NULL,
 164         NULL,
 165         NULL,
 166         &pts_info,
 167         NULL
 168 };
 169 
 170 static struct streamtab ptsinfo = {
 171         &ptsrint,
 172         &ptswint,
 173         NULL,
 174         NULL
 175 };
 176 
 177 static int pts_devinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
 178 static int pts_attach(dev_info_t *, ddi_attach_cmd_t);
 179 static int pts_detach(dev_info_t *, ddi_detach_cmd_t);
 180 
 181 #define PTS_CONF_FLAG   (D_NEW | D_MP)
 182 
 183 /*
 184  * this will define (struct cb_ops cb_pts_ops) and (struct dev_ops pts_ops)
 185  */
 186 DDI_DEFINE_STREAM_OPS(pts_ops, nulldev, nulldev,        \
 187     pts_attach, pts_detach, nodev,                      \
 188     pts_devinfo, PTS_CONF_FLAG, &ptsinfo, ddi_quiesce_not_supported);
 189 
 190 /*
 191  * Module linkage information for the kernel.
 192  */
 193 
 194 static struct modldrv modldrv = {
 195         &mod_driverops, /* Type of module.  This one is a pseudo driver */
 196         "Slave Stream Pseudo Terminal driver 'pts'",
 197         &pts_ops,   /* driver ops */
 198 };
 199 
 200 static struct modlinkage modlinkage = {
 201         MODREV_1,
 202         &modldrv,
 203         NULL
 204 };
 205 
 206 int
 207 _init(void)
 208 {
 209         int rc;
 210 
 211         if ((rc = mod_install(&modlinkage)) == 0)
 212                 ptms_init();
 213         return (rc);
 214 }
 215 
 216 
 217 int
 218 _fini(void)
 219 {
 220         return (mod_remove(&modlinkage));
 221 }
 222 
 223 int
 224 _info(struct modinfo *modinfop)
 225 {
 226         return (mod_info(&modlinkage, modinfop));
 227 }
 228 
 229 static int
 230 pts_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
 231 {
 232         if (cmd != DDI_ATTACH)
 233                 return (DDI_FAILURE);
 234 
 235         mutex_enter(&ptms_lock);
 236         pts_dip = devi;
 237         mutex_exit(&ptms_lock);
 238 
 239         return (DDI_SUCCESS);
 240 }
 241 
 242 /*ARGSUSED*/
 243 static int
 244 pts_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
 245 {
 246         if (cmd != DDI_DETACH)
 247                 return (DDI_FAILURE);
 248 
 249         /*
 250          * For now, pts cannot be detached.
 251          */
 252         return (DDI_FAILURE);
 253 }
 254 
 255 /*ARGSUSED*/
 256 static int
 257 pts_devinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
 258     void **result)
 259 {
 260         int error;
 261 
 262         switch (infocmd) {
 263         case DDI_INFO_DEVT2DEVINFO:
 264                 if (pts_dip == NULL) {
 265                         error = DDI_FAILURE;
 266                 } else {
 267                         *result = (void *)pts_dip;
 268                         error = DDI_SUCCESS;
 269                 }
 270                 break;
 271         case DDI_INFO_DEVT2INSTANCE:
 272                 *result = (void *)0;
 273                 error = DDI_SUCCESS;
 274                 break;
 275         default:
 276                 error = DDI_FAILURE;
 277         }
 278         return (error);
 279 }
 280 
 281 /* ARGSUSED */
 282 /*
 283  * Open the slave device. Reject a clone open and do not allow the
 284  * driver to be pushed. If the slave/master pair is locked or if
 285  * the master is not open, return EACCESS.
 286  * Upon success, store the write queue pointer in private data and
 287  * set the PTSOPEN bit in the pt_state field.
 288  */
 289 static int
 290 ptsopen(
 291         queue_t *rqp,           /* pointer to the read side queue */
 292         dev_t   *devp,          /* pointer to stream tail's dev */
 293         int     oflag,          /* the user open(2) supplied flags */
 294         int     sflag,          /* open state flag */
 295         cred_t  *credp)         /* credentials */
 296 {
 297         struct pt_ttys  *ptsp;
 298         mblk_t          *mp;
 299         mblk_t          *mop;   /* ptr to a setopts message block */
 300         minor_t         dminor = getminor(*devp);
 301         struct stroptions *sop;
 302 
 303         DDBG("entering ptsopen(%d)", dminor);
 304 
 305         if (sflag != 0) {
 306                 return (EINVAL);
 307         }
 308 
 309         mutex_enter(&ptms_lock);
 310         ptsp = ptms_minor2ptty(dminor);
 311 
 312         if (ptsp == NULL) {
 313                 mutex_exit(&ptms_lock);
 314                 return (ENXIO);
 315         }
 316         mutex_enter(&ptsp->pt_lock);
 317 
 318         /*
 319          * Prevent opens from zones other than the one blessed by ptm.  We
 320          * can't even allow the global zone to open all pts's, as it would
 321          * otherwise inproperly be able to claim pts's already opened by zones.
 322          */
 323         if (ptsp->pt_zoneid != getzoneid()) {
 324                 mutex_exit(&ptsp->pt_lock);
 325                 mutex_exit(&ptms_lock);
 326                 return (EPERM);
 327         }
 328 
 329         /*
 330          * Allow reopen of this device.
 331          */
 332         if (rqp->q_ptr != NULL) {
 333                 ASSERT(rqp->q_ptr == ptsp);
 334                 ASSERT(ptsp->pts_rdq == rqp);
 335                 mutex_exit(&ptsp->pt_lock);
 336                 mutex_exit(&ptms_lock);
 337                 return (0);
 338         }
 339 
 340         DDBGP("ptsopen: p = %p\n", (uintptr_t)ptsp);
 341         DDBG("ptsopen: state = %x\n", ptsp->pt_state);
 342 
 343         ASSERT(ptsp->pt_minor == dminor);
 344 
 345         if ((ptsp->pt_state & PTLOCK) || !(ptsp->pt_state & PTMOPEN)) {
 346                 mutex_exit(&ptsp->pt_lock);
 347                 mutex_exit(&ptms_lock);
 348                 return (EAGAIN);
 349         }
 350 
 351         /*
 352          * if already open, simply return...
 353          */
 354         if (ptsp->pt_state & PTSOPEN) {
 355                 ASSERT(rqp->q_ptr == ptsp);
 356                 ASSERT(ptsp->pts_rdq == rqp);
 357                 mutex_exit(&ptsp->pt_lock);
 358                 mutex_exit(&ptms_lock);
 359                 return (0);
 360         }
 361 
 362         /*
 363          * Allocate message block for setting stream head options.
 364          */
 365         if ((mop = allocb(sizeof (struct stroptions), BPRI_MED)) == NULL) {
 366                 mutex_exit(&ptsp->pt_lock);
 367                 mutex_exit(&ptms_lock);
 368                 return (ENOMEM);
 369         }
 370 
 371         /*
 372          * Slave should send zero-length message to a master when it is
 373          * closing. If memory is low at that time, master will not detect slave
 374          * closes, this pty will not be deallocated. So, preallocate this
 375          * zero-length message block early.
 376          */
 377         if ((mp = allocb(0, BPRI_MED)) == NULL) {
 378                 mutex_exit(&ptsp->pt_lock);
 379                 mutex_exit(&ptms_lock);
 380                 freemsg(mop);
 381                 return (ENOMEM);
 382         }
 383 
 384         ptsp->pt_state |= PTSOPEN;
 385 
 386         WR(rqp)->q_ptr = rqp->q_ptr = ptsp;
 387 
 388         mutex_exit(&ptsp->pt_lock);
 389         mutex_exit(&ptms_lock);
 390 
 391         if (ptsp->pt_state & PTSTTY)
 392                 STREAM(rqp)->sd_flag |= STRXPG4TTY;
 393 
 394         qprocson(rqp);
 395 
 396         /*
 397          * After qprocson pts driver is fully plumbed into the stream and can
 398          * send/receive messages. Setting pts_rdq will allow master side to send
 399          * messages to the slave. This setting can't occur before qprocson() is
 400          * finished because slave is not ready to process them.
 401          */
 402         PT_ENTER_WRITE(ptsp);
 403         ptsp->pts_rdq = rqp;
 404         ASSERT(ptsp->pt_nullmsg == NULL);
 405         ptsp->pt_nullmsg = mp;
 406         PT_EXIT_WRITE(ptsp);
 407 
 408         /*
 409          * set up hi/lo water marks on stream head read queue
 410          * and add controlling tty if not set
 411          */
 412 
 413         mop->b_datap->db_type = M_SETOPTS;
 414         mop->b_wptr += sizeof (struct stroptions);
 415         sop = (struct stroptions *)mop->b_rptr;
 416         sop->so_flags = SO_HIWAT | SO_LOWAT | SO_ISTTY;
 417         sop->so_hiwat = _TTY_BUFSIZ;
 418         sop->so_lowat = 256;
 419         putnext(rqp, mop);
 420 
 421         return (0);
 422 }
 423 
 424 /*
 425  * Find the address to private data identifying the slave's write
 426  * queue. Send a 0-length msg up the slave's read queue to designate
 427  * the master is closing. Uattach the master from the slave by nulling
 428  * out master's write queue field in private data.
 429  */
 430 /*ARGSUSED1*/
 431 static int
 432 ptsclose(queue_t *rqp, int flag, cred_t *credp)
 433 {
 434         struct pt_ttys  *ptsp;
 435         queue_t *wqp;
 436         mblk_t  *mp;
 437         mblk_t  *bp;
 438 
 439         /*
 440          * q_ptr should never be NULL in the close routine and it is checked in
 441          * DEBUG kernel by ASSERT. For non-DEBUG kernel the attempt is made to
 442          * behave gracefully.
 443          */
 444         ASSERT(rqp->q_ptr != NULL);
 445         if (rqp->q_ptr == NULL) {
 446                 qprocsoff(rqp);
 447                 return (0);
 448         }
 449 
 450         ptsp = (struct pt_ttys *)rqp->q_ptr;
 451 
 452         /*
 453          * Slave is going to close and doesn't want any new  messages coming
 454          * from the master side, so set pts_rdq to NULL. This should be done
 455          * before call to qprocsoff() since slave can't process additional
 456          * messages from the master after qprocsoff is called.
 457          */
 458         PT_ENTER_WRITE(ptsp);
 459         mp = ptsp->pt_nullmsg;
 460         ptsp->pt_nullmsg = NULL;
 461         ptsp->pts_rdq = NULL;
 462         PT_EXIT_WRITE(ptsp);
 463 
 464         /*
 465          * Drain the ouput
 466          */
 467         wqp = WR(rqp);
 468         PT_ENTER_READ(ptsp);
 469         while ((bp = getq(wqp)) != NULL) {
 470                 if (ptsp->ptm_rdq) {
 471                         putnext(ptsp->ptm_rdq, bp);
 472                 } else if (bp->b_datap->db_type == M_IOCTL) {
 473                         bp->b_datap->db_type = M_IOCNAK;
 474                         freemsg(bp->b_cont);
 475                         bp->b_cont = NULL;
 476                         qreply(wqp, bp);
 477                 } else {
 478                         freemsg(bp);
 479                 }
 480         }
 481         /*
 482          * qenable master side write queue so that it can flush
 483          * its messages as slaves's read queue is going away
 484          */
 485         if (ptsp->ptm_rdq) {
 486                 if (mp)
 487                         putnext(ptsp->ptm_rdq, mp);
 488                 else
 489                         qenable(WR(ptsp->ptm_rdq));
 490         } else
 491                 freemsg(mp);
 492         PT_EXIT_READ(ptsp);
 493 
 494         qprocsoff(rqp);
 495 
 496         rqp->q_ptr = NULL;
 497         WR(rqp)->q_ptr = NULL;
 498 
 499         ptms_close(ptsp, PTSOPEN | PTSTTY);
 500 
 501         return (0);
 502 }
 503 
 504 
 505 /*
 506  * The wput procedure will only handle flush messages.
 507  * All other messages are queued and the write side
 508  * service procedure sends them off to the master side.
 509  */
 510 static int
 511 ptswput(queue_t *qp, mblk_t *mp)
 512 {
 513         struct pt_ttys *ptsp;
 514         struct iocblk  *iocp;
 515         unsigned char type = mp->b_datap->db_type;
 516 
 517         DBG(("entering ptswput\n"));
 518         ASSERT(qp->q_ptr);
 519 
 520         ptsp = (struct pt_ttys *)qp->q_ptr;
 521         PT_ENTER_READ(ptsp);
 522         if (ptsp->ptm_rdq == NULL) {
 523                 DBG(("in write put proc but no master\n"));
 524                 /*
 525                  * NAK ioctl as slave side read queue is gone.
 526                  * Or else free the message.
 527                  */
 528                 if (mp->b_datap->db_type == M_IOCTL) {
 529                         mp->b_datap->db_type = M_IOCNAK;
 530                         freemsg(mp->b_cont);
 531                         mp->b_cont = NULL;
 532                         qreply(qp, mp);
 533                 } else
 534                         freemsg(mp);
 535                 PT_EXIT_READ(ptsp);
 536                 return (0);
 537         }
 538 
 539         if (type >= QPCTL) {
 540                 switch (type) {
 541 
 542                 /*
 543                  * if write queue request, flush slave's write
 544                  * queue and send FLUSHR to ptm. If read queue
 545                  * request, send FLUSHR to ptm.
 546                  */
 547                 case M_FLUSH:
 548                 DBG(("pts got flush request\n"));
 549                 if (*mp->b_rptr & FLUSHW) {
 550 
 551                         DBG(("got FLUSHW, flush pts write Q\n"));
 552                         if (*mp->b_rptr & FLUSHBAND)
 553                                 /*
 554                                  * if it is a FLUSHBAND, do flushband.
 555                                  */
 556                                 flushband(qp, *(mp->b_rptr + 1), FLUSHDATA);
 557                         else
 558                                 flushq(qp, FLUSHDATA);
 559 
 560                         *mp->b_rptr &= ~FLUSHW;
 561                         if ((*mp->b_rptr & FLUSHR) == 0) {
 562                                 /*
 563                                  * FLUSHW only. Change to FLUSHR and putnext
 564                                  * to ptm, then we are done.
 565                                  */
 566                                 *mp->b_rptr |= FLUSHR;
 567                                 if (ptsp->ptm_rdq)
 568                                         putnext(ptsp->ptm_rdq, mp);
 569                                 break;
 570                         } else {
 571                                 mblk_t *nmp;
 572 
 573                                 /* It is a FLUSHRW. Duplicate the mblk */
 574                                 nmp = copyb(mp);
 575                                 if (nmp) {
 576                                         /*
 577                                          * Change FLUSHW to FLUSHR before
 578                                          * putnext to ptm.
 579                                          */
 580                                         DBG(("putnext nmp(FLUSHR) to ptm\n"));
 581                                         *nmp->b_rptr |= FLUSHR;
 582                                         if (ptsp->ptm_rdq)
 583                                                 putnext(ptsp->ptm_rdq, nmp);
 584                                 }
 585                         }
 586                 }
 587                 /*
 588                  * Since the packet module will toss any
 589                  * M_FLUSHES sent to the master's stream head
 590                  * read queue, we simply turn it around here.
 591                  */
 592                 if (*mp->b_rptr & FLUSHR) {
 593                         ASSERT(RD(qp)->q_first == NULL);
 594                         DBG(("qreply(qp) turning FLUSHR around\n"));
 595                         qreply(qp, mp);
 596                 } else {
 597                         freemsg(mp);
 598                 }
 599                 break;
 600 
 601                 case M_READ:
 602                 /* Caused by ldterm - can not pass to master */
 603                 freemsg(mp);
 604                 break;
 605 
 606                 default:
 607                 if (ptsp->ptm_rdq)
 608                         putnext(ptsp->ptm_rdq, mp);
 609                 break;
 610                 }
 611                 PT_EXIT_READ(ptsp);
 612                 return (0);
 613         }
 614 
 615         switch (type) {
 616 
 617         case M_IOCTL:
 618                 /*
 619                  * For case PTSSTTY set the flag PTSTTY and ACK
 620                  * the ioctl so that the user program can push
 621                  * the associated modules to get tty semantics.
 622                  * See bugid 4025044
 623                  */
 624                 iocp = (struct iocblk *)mp->b_rptr;
 625                 switch (iocp->ioc_cmd) {
 626                 default:
 627                         break;
 628 
 629                 case PTSSTTY:
 630                         if (ptsp->pt_state & PTSTTY) {
 631                                 mp->b_datap->db_type = M_IOCNAK;
 632                                 iocp->ioc_error = EEXIST;
 633                         } else {
 634                                 mp->b_datap->db_type = M_IOCACK;
 635                                 mutex_enter(&ptsp->pt_lock);
 636                                 ptsp->pt_state |= PTSTTY;
 637                                 mutex_exit(&ptsp->pt_lock);
 638                                 iocp->ioc_error = 0;
 639                         }
 640                         iocp->ioc_count = 0;
 641                         qreply(qp, mp);
 642                         PT_EXIT_READ(ptsp);
 643                         return (0);
 644                 }
 645                 /* FALLTHROUGH */
 646         default:
 647                 /*
 648                  * send other messages to the master
 649                  */
 650                 DBG(("put msg on slave's write queue\n"));
 651                 (void) putq(qp, mp);
 652                 break;
 653         }
 654 
 655         PT_EXIT_READ(ptsp);
 656         DBG(("return from ptswput()\n"));
 657         return (0);
 658 }
 659 
 660 
 661 /*
 662  * enable the write side of the master. This triggers the
 663  * master to send any messages queued on its write side to
 664  * the read side of this slave.
 665  */
 666 static int
 667 ptsrsrv(queue_t *qp)
 668 {
 669         struct pt_ttys *ptsp;
 670 
 671         DBG(("entering ptsrsrv\n"));
 672         ASSERT(qp->q_ptr);
 673 
 674         ptsp = (struct pt_ttys *)qp->q_ptr;
 675         PT_ENTER_READ(ptsp);
 676         if (ptsp->ptm_rdq == NULL) {
 677                 DBG(("in read srv proc but no master\n"));
 678                 PT_EXIT_READ(ptsp);
 679                 return (0);
 680         }
 681         qenable(WR(ptsp->ptm_rdq));
 682         PT_EXIT_READ(ptsp);
 683         DBG(("leaving ptsrsrv\n"));
 684         return (0);
 685 }
 686 
 687 /*
 688  * If there are messages on this queue that can be sent to
 689  * master, send them via putnext(). Else, if queued messages
 690  * cannot be sent, leave them on this queue. If priority
 691  * messages on this queue, send them to master no matter what.
 692  */
 693 static int
 694 ptswsrv(queue_t *qp)
 695 {
 696         struct pt_ttys *ptsp;
 697         queue_t *ptm_rdq;
 698         mblk_t *mp;
 699 
 700         DBG(("entering ptswsrv\n"));
 701         ASSERT(qp->q_ptr);
 702 
 703         ptsp = (struct pt_ttys *)qp->q_ptr;
 704         PT_ENTER_READ(ptsp);
 705         if (ptsp->ptm_rdq == NULL) {
 706                 DBG(("in write srv proc but no master\n"));
 707                 /*
 708                  * Free messages on the write queue and send
 709                  * NAK for any M_IOCTL type messages to wakeup
 710                  * the user process waiting for ACK/NAK from
 711                  * the ioctl invocation
 712                  */
 713                 while ((mp = getq(qp)) != NULL) {
 714                         if (mp->b_datap->db_type == M_IOCTL) {
 715                                 mp->b_datap->db_type = M_IOCNAK;
 716                                 freemsg(mp->b_cont);
 717                                 mp->b_cont = NULL;
 718                                 qreply(qp, mp);
 719                         } else
 720                                 freemsg(mp);
 721                 }
 722                 PT_EXIT_READ(ptsp);
 723                 return (0);
 724         } else {
 725                 ptm_rdq = ptsp->ptm_rdq;
 726         }
 727 
 728         /*
 729          * while there are messages on this write queue...
 730          */
 731         while ((mp = getq(qp)) != NULL) {
 732                 /*
 733                  * if don't have control message and cannot put
 734                  * msg. on master's read queue, put it back on
 735                  * this queue.
 736                  */
 737                 if (mp->b_datap->db_type <= QPCTL &&
 738                     !bcanputnext(ptm_rdq, mp->b_band)) {
 739                         DBG(("put msg. back on Q\n"));
 740                         (void) putbq(qp, mp);
 741                         break;
 742                 }
 743                 /*
 744                  * else send the message up master's stream
 745                  */
 746                 DBG(("send message to master\n"));
 747                 putnext(ptm_rdq, mp);
 748         }
 749         DBG(("leaving ptswsrv\n"));
 750         PT_EXIT_READ(ptsp);
 751         return (0);
 752 }