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