Print this page
12306 XPG4v2 slave pty behaviour should generally be disabled
Reviewed by: Robert Mustacchi <rm@fingolfin.org>
Change-ID: I7ccd399c22866f34dd20c6bb9d28e77ba4e24c67


   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 
  30 /*
  31  * Pseudo Terminal Slave Driver.
  32  *
  33  * The pseudo-tty subsystem simulates a terminal connection, where the master
  34  * side represents the terminal and the slave represents the user process's
  35  * special device end point. The master device is set up as a cloned device
  36  * where its major device number is the major for the clone device and its minor
  37  * device number is the major for the ptm driver. There are no nodes in the file
  38  * system for master devices. The master pseudo driver is opened using the
  39  * open(2) system call with /dev/ptmx as the device parameter.  The clone open
  40  * finds the next available minor device for the ptm major device.
  41  *
  42  * A master device is available only if it and its corresponding slave device
  43  * are not already open. When the master device is opened, the corresponding
  44  * slave device is automatically locked out. Only one open is allowed on a
  45  * master device.  Multiple opens are allowed on the slave device.  After both
  46  * the master and slave have been opened, the user has two file descriptors
  47  * which are the end points of a full duplex connection composed of two streams
  48  * which are automatically connected at the master and slave drivers. The user
  49  * may then push modules onto either side of the stream pair.


  89  *   NULL before qprocsoff() is called during close.
  90  *
  91  *   The pt_nullmsg field is only used in open/close routines and it is also
  92  *   protected by PT_ENTER_WRITE/PT_EXIT_WRITE brackets to avoid extra mutex
  93  *   holds.
  94  *
  95  * Lock Ordering:
  96  *
  97  *   If both ptms_lock and per-pty lock should be held, ptms_lock should always
  98  *   be entered first, followed by per-pty lock.
  99  *
 100  * See ptms.h, ptm.c and ptms_conf.c fore more information.
 101  *
 102  */
 103 
 104 #include <sys/types.h>
 105 #include <sys/param.h>
 106 #include <sys/sysmacros.h>
 107 #include <sys/stream.h>
 108 #include <sys/stropts.h>

 109 #include <sys/stat.h>
 110 #include <sys/errno.h>
 111 #include <sys/debug.h>
 112 #include <sys/cmn_err.h>
 113 #include <sys/ptms.h>
 114 #include <sys/systm.h>
 115 #include <sys/modctl.h>
 116 #include <sys/conf.h>
 117 #include <sys/ddi.h>
 118 #include <sys/sunddi.h>
 119 #include <sys/cred.h>
 120 #include <sys/zone.h>
 121 
 122 #ifdef DEBUG
 123 int pts_debug = 0;
 124 #define DBG(a)   if (pts_debug) cmn_err(CE_NOTE, a)
 125 #else
 126 #define DBG(a)
 127 #endif
 128 


 320         if (ptsp->pt_zoneid != getzoneid()) {
 321                 mutex_exit(&ptsp->pt_lock);
 322                 mutex_exit(&ptms_lock);
 323                 return (EPERM);
 324         }
 325 
 326         /*
 327          * Allow reopen of this device.
 328          */
 329         if (rqp->q_ptr != NULL) {
 330                 ASSERT(rqp->q_ptr == ptsp);
 331                 ASSERT(ptsp->pts_rdq == rqp);
 332                 mutex_exit(&ptsp->pt_lock);
 333                 mutex_exit(&ptms_lock);
 334                 return (0);
 335         }
 336 
 337         DDBGP("ptsopen: p = %p\n", (uintptr_t)ptsp);
 338         DDBG("ptsopen: state = %x\n", ptsp->pt_state);
 339 
 340 
 341         ASSERT(ptsp->pt_minor == dminor);
 342 
 343         if ((ptsp->pt_state & PTLOCK) || !(ptsp->pt_state & PTMOPEN)) {
 344                 mutex_exit(&ptsp->pt_lock);
 345                 mutex_exit(&ptms_lock);
 346                 return (EAGAIN);
 347         }
 348 
 349         /*
 350          * if already, open simply return...
 351          */
 352         if (ptsp->pt_state & PTSOPEN) {
 353                 ASSERT(rqp->q_ptr == ptsp);
 354                 ASSERT(ptsp->pts_rdq == rqp);
 355                 mutex_exit(&ptsp->pt_lock);
 356                 mutex_exit(&ptms_lock);
 357                 return (0);
 358         }
 359 
 360         /*
 361          * Allocate message block for setting stream head options.
 362          */
 363         if ((mop = allocb(sizeof (struct stroptions), BPRI_MED)) == NULL) {
 364                 mutex_exit(&ptsp->pt_lock);
 365                 mutex_exit(&ptms_lock);
 366                 return (ENOMEM);
 367         }
 368 
 369         /*
 370          * Slave should send zero-length message to a master when it is
 371          * closing. If memory is low at that time, master will not detect slave
 372          * closes, this pty will not be deallocated. So, preallocate this
 373          * zero-length message block early.
 374          */
 375         if ((mp = allocb(0, BPRI_MED)) == NULL) {
 376                 mutex_exit(&ptsp->pt_lock);
 377                 mutex_exit(&ptms_lock);
 378                 freemsg(mop);
 379                 return (ENOMEM);
 380         }
 381 
 382         ptsp->pt_state |= PTSOPEN;
 383 
 384         WR(rqp)->q_ptr = rqp->q_ptr = ptsp;
 385 
 386         mutex_exit(&ptsp->pt_lock);
 387         mutex_exit(&ptms_lock);
 388 



 389         qprocson(rqp);
 390 
 391         /*
 392          * After qprocson pts driver is fully plumbed into the stream and can
 393          * send/receive messages. Setting pts_rdq will allow master side to send
 394          * messages to the slave. This setting can't occur before qprocson() is
 395          * finished because slave is not ready to process them.
 396          */
 397         PT_ENTER_WRITE(ptsp);
 398         ptsp->pts_rdq = rqp;
 399         ASSERT(ptsp->pt_nullmsg == NULL);
 400         ptsp->pt_nullmsg = mp;
 401         PT_EXIT_WRITE(ptsp);
 402 
 403         /*
 404          * set up hi/lo water marks on stream head read queue
 405          * and add controlling tty if not set
 406          */
 407 
 408         mop->b_datap->db_type = M_SETOPTS;
 409         mop->b_wptr += sizeof (struct stroptions);
 410         sop = (struct stroptions *)mop->b_rptr;
 411         sop->so_flags = SO_HIWAT | SO_LOWAT | SO_ISTTY;
 412         sop->so_hiwat = _TTY_BUFSIZ;
 413         sop->so_lowat = 256;
 414         putnext(rqp, mop);
 415 
 416         return (0);
 417 }
 418 
 419 
 420 
 421 /*
 422  * Find the address to private data identifying the slave's write
 423  * queue. Send a 0-length msg up the slave's read queue to designate
 424  * the master is closing. Uattach the master from the slave by nulling
 425  * out master's write queue field in private data.
 426  */
 427 /*ARGSUSED1*/
 428 static int
 429 ptsclose(queue_t *rqp, int flag, cred_t *credp)
 430 {
 431         struct pt_ttys  *ptsp;
 432         queue_t *wqp;
 433         mblk_t  *mp;
 434         mblk_t  *bp;
 435 
 436         /*
 437          * q_ptr should never be NULL in the close routine and it is checked in
 438          * DEBUG kernel by ASSERT. For non-DEBUG kernel the attempt is made to
 439          * behave gracefully.
 440          */




   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.


  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 


 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          */