Print this page
    
9042 multiples of tty streams modules cause weirdness
Reviewed by: Randy Fishel <randyf@sibernet.com>
Reviewed by: Carlos Neira <cneirabustos@gmail.com>
Approved by: Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org>
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/uts/common/io/ptem.c
          +++ new/usr/src/uts/common/io/ptem.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, Version 1.0 only
   6    6   * (the "License").  You may not use this file except in compliance
   7    7   * with the License.
   8    8   *
   9    9   * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  10   10   * or http://www.opensolaris.org/os/licensing.
  11   11   * See the License for the specific language governing permissions
  12   12   * and limitations under the License.
  13   13   *
  14   14   * When distributing Covered Code, include this CDDL HEADER in each
  15   15   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  16   16   * If applicable, add the following below this CDDL HEADER, with the
  17   17   * fields enclosed by brackets "[]" replaced with your own identifying
  18   18   * information: Portions Copyright [yyyy] [name of copyright owner]
  
    | 
      ↓ open down ↓ | 
    18 lines elided | 
    
      ↑ open up ↑ | 
  
  19   19   *
  20   20   * CDDL HEADER END
  21   21   */
  22   22  /*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
  23   23  /*        All Rights Reserved   */
  24   24  
  25   25  
  26   26  /*
  27   27   * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
  28   28   * Use is subject to license terms.
       29 + * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
  29   30   */
  30   31  
  31   32  /*
  32   33   * Description:
  33   34   *
  34   35   * The PTEM streams module is used as a pseudo driver emulator.  Its purpose
  35   36   * is to emulate the ioctl() functions of a terminal device driver.
  36   37   */
  37   38  
  38   39  #include <sys/types.h>
  39   40  #include <sys/param.h>
  40   41  #include <sys/stream.h>
  41   42  #include <sys/stropts.h>
  42   43  #include <sys/strsun.h>
  43   44  #include <sys/termio.h>
  44   45  #include <sys/pcb.h>
  45   46  #include <sys/signal.h>
  46   47  #include <sys/cred.h>
  47   48  #include <sys/strtty.h>
  48   49  #include <sys/errno.h>
  49   50  #include <sys/cmn_err.h>
  50   51  #include <sys/jioctl.h>
  51   52  #include <sys/ptem.h>
  52   53  #include <sys/ptms.h>
  53   54  #include <sys/debug.h>
  54   55  #include <sys/kmem.h>
  
    | 
      ↓ open down ↓ | 
    16 lines elided | 
    
      ↑ open up ↑ | 
  
  55   56  #include <sys/ddi.h>
  56   57  #include <sys/sunddi.h>
  57   58  #include <sys/conf.h>
  58   59  #include <sys/modctl.h>
  59   60  
  60   61  extern struct streamtab pteminfo;
  61   62  
  62   63  static struct fmodsw fsw = {
  63   64          "ptem",
  64   65          &pteminfo,
  65      -        D_MTQPAIR | D_MP
       66 +        D_MTQPAIR | D_MP | _D_SINGLE_INSTANCE
  66   67  };
  67   68  
  68   69  static struct modlstrmod modlstrmod = {
  69   70          &mod_strmodops, "pty hardware emulator", &fsw
  70   71  };
  71   72  
  72   73  static struct modlinkage modlinkage = {
  73   74          MODREV_1, &modlstrmod, NULL
  74   75  };
  75   76  
  76   77  int
  77   78  _init()
  78   79  {
  79   80          return (mod_install(&modlinkage));
  80   81  }
  81   82  
  82   83  int
  83   84  _fini()
  84   85  {
  85   86          return (mod_remove(&modlinkage));
  86   87  }
  87   88  
  88   89  int
  89   90  _info(struct modinfo *modinfop)
  90   91  {
  91   92          return (mod_info(&modlinkage, modinfop));
  92   93  }
  93   94  
  94   95  /*
  95   96   * stream data structure definitions
  96   97   */
  97   98  static int ptemopen(queue_t *, dev_t  *, int, int, cred_t *);
  98   99  static int ptemclose(queue_t *, int, cred_t *);
  99  100  static void ptemrput(queue_t *, mblk_t *);
 100  101  static void ptemwput(queue_t *, mblk_t *);
 101  102  static void ptemwsrv(queue_t *);
 102  103  
 103  104  static struct module_info ptem_info = {
 104  105          0xabcd,
 105  106          "ptem",
 106  107          0,
 107  108          _TTY_BUFSIZ,
 108  109          _TTY_BUFSIZ,
 109  110          128
 110  111  };
 111  112  
 112  113  static struct qinit ptemrinit = {
 113  114          (int (*)()) ptemrput,
 114  115          NULL,
 115  116          ptemopen,
 116  117          ptemclose,
 117  118          NULL,
 118  119          &ptem_info,
 119  120          NULL
 120  121  };
 121  122  
 122  123  static struct qinit ptemwinit = {
 123  124          (int (*)()) ptemwput,
 124  125          (int (*)()) ptemwsrv,
 125  126          ptemopen,
 126  127          ptemclose,
 127  128          nulldev,
 128  129          &ptem_info,
 129  130          NULL
 130  131  };
 131  132  
 132  133  struct streamtab pteminfo = {
 133  134          &ptemrinit,
 134  135          &ptemwinit,
 135  136          NULL,
 136  137          NULL
 137  138  };
 138  139  
 139  140  static void     ptioc(queue_t *, mblk_t *, int);
 140  141  static int      ptemwmsg(queue_t *, mblk_t *);
 141  142  
 142  143  /*
 143  144   * ptemopen - open routine gets called when the module gets pushed onto the
 144  145   * stream.
 145  146   */
 146  147  /* ARGSUSED */
 147  148  static int
 148  149  ptemopen(
 149  150          queue_t    *q,          /* pointer to the read side queue */
 150  151          dev_t   *devp,          /* pointer to stream tail's dev */
 151  152          int     oflag,          /* the user open(2) supplied flags */
 152  153          int     sflag,          /* open state flag */
 153  154          cred_t *credp)          /* credentials */
 154  155  {
 155  156          struct ptem *ntp;       /* ptem entry for this PTEM module */
 156  157          mblk_t *mop;            /* an setopts mblk */
 157  158          struct stroptions *sop;
 158  159          struct termios *termiosp;
 159  160          int len;
 160  161  
 161  162          if (sflag != MODOPEN)
 162  163                  return (EINVAL);
 163  164  
 164  165          if (q->q_ptr != NULL) {
 165  166                  /* It's already attached. */
 166  167                  return (0);
 167  168          }
 168  169  
 169  170          /*
 170  171           * Allocate state structure.
 171  172           */
 172  173          ntp = kmem_alloc(sizeof (*ntp), KM_SLEEP);
 173  174  
 174  175          /*
 175  176           * Allocate a message block, used to pass the zero length message for
 176  177           * "stty 0".
 177  178           *
 178  179           * NOTE: it's better to find out if such a message block can be
 179  180           *       allocated before it's needed than to not be able to
 180  181           *       deliver (for possible lack of buffers) when a hang-up
 181  182           *       occurs.
 182  183           */
 183  184          if ((ntp->dack_ptr = allocb(4, BPRI_MED)) == NULL) {
 184  185                  kmem_free(ntp, sizeof (*ntp));
 185  186                  return (EAGAIN);
 186  187          }
 187  188  
 188  189          /*
 189  190           * Initialize an M_SETOPTS message to set up hi/lo water marks on
 190  191           * stream head read queue and add controlling tty if not set.
 191  192           */
 192  193          mop = allocb(sizeof (struct stroptions), BPRI_MED);
 193  194          if (mop == NULL) {
 194  195                  freemsg(ntp->dack_ptr);
 195  196                  kmem_free(ntp, sizeof (*ntp));
 196  197                  return (EAGAIN);
 197  198          }
 198  199          mop->b_datap->db_type = M_SETOPTS;
 199  200          mop->b_wptr += sizeof (struct stroptions);
 200  201          sop = (struct stroptions *)mop->b_rptr;
 201  202          sop->so_flags = SO_HIWAT | SO_LOWAT | SO_ISTTY;
 202  203          sop->so_hiwat = _TTY_BUFSIZ;
 203  204          sop->so_lowat = 256;
 204  205  
 205  206          /*
 206  207           * Cross-link.
 207  208           */
 208  209          ntp->q_ptr = q;
 209  210          q->q_ptr = ntp;
 210  211          WR(q)->q_ptr = ntp;
 211  212  
 212  213          /*
 213  214           * Get termios defaults.  These are stored as
 214  215           * a property in the "options" node.
 215  216           */
 216  217          if (ddi_getlongprop(DDI_DEV_T_ANY, ddi_root_node(), 0, "ttymodes",
 217  218              (caddr_t)&termiosp, &len) == DDI_PROP_SUCCESS &&
 218  219              len == sizeof (struct termios)) {
 219  220  
 220  221                  ntp->cflags = termiosp->c_cflag;
 221  222                  kmem_free(termiosp, len);
 222  223          } else {
 223  224                  /*
 224  225                   * Gack!  Whine about it.
 225  226                   */
 226  227                  cmn_err(CE_WARN, "ptem: Couldn't get ttymodes property!");
 227  228          }
 228  229          ntp->wsz.ws_row = 0;
 229  230          ntp->wsz.ws_col = 0;
 230  231          ntp->wsz.ws_xpixel = 0;
 231  232          ntp->wsz.ws_ypixel = 0;
 232  233  
 233  234          ntp->state = 0;
 234  235  
 235  236          /*
 236  237           * Commit to the open and send the M_SETOPTS off to the stream head.
 237  238           */
 238  239          qprocson(q);
 239  240          putnext(q, mop);
 240  241  
 241  242          return (0);
 242  243  }
 243  244  
 244  245  
 245  246  /*
 246  247   * ptemclose - This routine gets called when the module gets popped off of the
 247  248   * stream.
 248  249   */
 249  250  /* ARGSUSED */
 250  251  static int
 251  252  ptemclose(queue_t *q, int flag, cred_t *credp)
 252  253  {
 253  254          struct ptem *ntp;       /* ptem entry for this PTEM module */
 254  255  
 255  256          qprocsoff(q);
 256  257          ntp = (struct ptem *)q->q_ptr;
 257  258          freemsg(ntp->dack_ptr);
 258  259          kmem_free(ntp, sizeof (*ntp));
 259  260          q->q_ptr = WR(q)->q_ptr = NULL;
 260  261          return (0);
 261  262  }
 262  263  
 263  264  
 264  265  /*
 265  266   * ptemrput - Module read queue put procedure.
 266  267   *
 267  268   * This is called from the module or driver downstream.
 268  269   */
 269  270  static void
 270  271  ptemrput(queue_t *q, mblk_t *mp)
 271  272  {
 272  273          struct iocblk *iocp;    /* M_IOCTL data */
 273  274          struct copyresp *resp;  /* transparent ioctl response struct */
 274  275          int error;
 275  276  
 276  277          switch (mp->b_datap->db_type) {
 277  278          case M_DELAY:
 278  279          case M_READ:
 279  280                  freemsg(mp);
 280  281                  break;
 281  282  
 282  283          case M_IOCTL:
 283  284                  iocp = (struct iocblk *)mp->b_rptr;
 284  285  
 285  286                  switch (iocp->ioc_cmd) {
 286  287                  case TCSBRK:
 287  288                          /*
 288  289                           * Send a break message upstream.
 289  290                           *
 290  291                           * XXX: Shouldn't the argument come into play in
 291  292                           *      determining whether or not so send an M_BREAK?
 292  293                           *      It certainly does in the write-side direction.
 293  294                           */
 294  295                          error = miocpullup(mp, sizeof (int));
 295  296                          if (error != 0) {
 296  297                                  miocnak(q, mp, 0, error);
 297  298                                  break;
 298  299                          }
 299  300                          if (!(*(int *)mp->b_cont->b_rptr)) {
 300  301                                  if (!putnextctl(q, M_BREAK)) {
 301  302                                          /*
 302  303                                           * Send an NAK reply back
 303  304                                           */
 304  305                                          miocnak(q, mp, 0, EAGAIN);
 305  306                                          break;
 306  307                                  }
 307  308                          }
 308  309                          /*
 309  310                           * ACK it.
 310  311                           */
 311  312                          mioc2ack(mp, NULL, 0, 0);
 312  313                          qreply(q, mp);
 313  314                          break;
 314  315  
 315  316                  case JWINSIZE:
 316  317                  case TIOCGWINSZ:
 317  318                  case TIOCSWINSZ:
 318  319                          ptioc(q, mp, RDSIDE);
 319  320                          break;
 320  321  
 321  322                  case TIOCSIGNAL:
 322  323                          /*
 323  324                           * The following subtle logic is due to the fact that
 324  325                           * `mp' may be in any one of three distinct formats:
 325  326                           *
 326  327                           *      1. A transparent M_IOCTL with an intptr_t-sized
 327  328                           *         payload containing the signal number.
 328  329                           *
 329  330                           *      2. An I_STR M_IOCTL with an int-sized payload
 330  331                           *         containing the signal number.
 331  332                           *
 332  333                           *      3. An M_IOCDATA with an int-sized payload
 333  334                           *         containing the signal number.
 334  335                           */
 335  336                          if (iocp->ioc_count == TRANSPARENT) {
 336  337                                  intptr_t sig = *(intptr_t *)mp->b_cont->b_rptr;
 337  338  
 338  339                                  if (sig < 1 || sig >= NSIG) {
 339  340                                          /*
 340  341                                           * it's transparent with pointer
 341  342                                           * to the arg
 342  343                                           */
 343  344                                          mcopyin(mp, NULL, sizeof (int), NULL);
 344  345                                          qreply(q, mp);
 345  346                                          break;
 346  347                                  }
 347  348                          }
 348  349                          ptioc(q, mp, RDSIDE);
 349  350                          break;
 350  351  
 351  352                  case TIOCREMOTE:
 352  353                          if (iocp->ioc_count != TRANSPARENT)
 353  354                                  ptioc(q, mp, RDSIDE);
 354  355                          else {
 355  356                                  mcopyin(mp, NULL, sizeof (int), NULL);
 356  357                                  qreply(q, mp);
 357  358                          }
 358  359                          break;
 359  360  
 360  361                  default:
 361  362                          putnext(q, mp);
 362  363                          break;
 363  364                  }
 364  365                  break;
 365  366  
 366  367          case M_IOCDATA:
 367  368                  resp = (struct copyresp *)mp->b_rptr;
 368  369                  if (resp->cp_rval) {
 369  370                          /*
 370  371                           * Just free message on failure.
 371  372                           */
 372  373                          freemsg(mp);
 373  374                          break;
 374  375                  }
 375  376  
 376  377                  /*
 377  378                   * Only need to copy data for the SET case.
 378  379                   */
 379  380                  switch (resp->cp_cmd) {
 380  381  
 381  382                  case TIOCSWINSZ:
 382  383                  case TIOCSIGNAL:
 383  384                  case TIOCREMOTE:
 384  385                          ptioc(q, mp, RDSIDE);
 385  386                          break;
 386  387  
 387  388                  case JWINSIZE:
 388  389                  case TIOCGWINSZ:
 389  390                          mp->b_datap->db_type = M_IOCACK;
 390  391                          mioc2ack(mp, NULL, 0, 0);
 391  392                          qreply(q, mp);
 392  393                          break;
 393  394  
 394  395                  default:
 395  396                          freemsg(mp);
 396  397                          break;
 397  398          }
 398  399          break;
 399  400  
 400  401          case M_IOCACK:
 401  402          case M_IOCNAK:
 402  403                  /*
 403  404                   * We only pass write-side ioctls through to the master that
 404  405                   * we've already ACKed or NAKed to the stream head.  Thus, we
 405  406                   * discard ones arriving from below, since they're redundant
 406  407                   * from the point of view of modules above us.
 407  408                   */
 408  409                  freemsg(mp);
 409  410                  break;
 410  411  
 411  412          case M_HANGUP:
 412  413                  /*
 413  414                   * clear blocked state.
 414  415                   */
 415  416                  {
 416  417                          struct ptem *ntp = (struct ptem *)q->q_ptr;
 417  418                          if (ntp->state & OFLOW_CTL) {
 418  419                                  ntp->state &= ~OFLOW_CTL;
 419  420                                  qenable(WR(q));
 420  421                          }
 421  422                  }
 422  423          default:
 423  424                  putnext(q, mp);
 424  425                  break;
 425  426          }
 426  427  }
 427  428  
 428  429  
 429  430  /*
 430  431   * ptemwput - Module write queue put procedure.
 431  432   *
 432  433   * This is called from the module or stream head upstream.
 433  434   *
 434  435   * XXX: This routine is quite lazy about handling allocation failures,
 435  436   *      basically just giving up and reporting failure.  It really ought to
 436  437   *      set up bufcalls and only fail when it's absolutely necessary.
 437  438   */
 438  439  static void
 439  440  ptemwput(queue_t *q, mblk_t *mp)
 440  441  {
 441  442          struct ptem *ntp = (struct ptem *)q->q_ptr;
 442  443          struct iocblk *iocp;    /* outgoing ioctl structure */
 443  444          struct copyresp *resp;
 444  445          unsigned char type = mp->b_datap->db_type;
 445  446  
 446  447          if (type >= QPCTL) {
 447  448                  switch (type) {
 448  449  
 449  450                  case M_IOCDATA:
 450  451                          resp = (struct copyresp *)mp->b_rptr;
 451  452                          if (resp->cp_rval) {
 452  453                                  /*
 453  454                                   * Just free message on failure.
 454  455                                   */
 455  456                                  freemsg(mp);
 456  457                                  break;
 457  458                          }
 458  459  
 459  460                          /*
 460  461                           * Only need to copy data for the SET case.
 461  462                           */
 462  463                          switch (resp->cp_cmd) {
 463  464  
 464  465                                  case TIOCSWINSZ:
 465  466                                          ptioc(q, mp, WRSIDE);
 466  467                                          break;
 467  468  
 468  469                                  case JWINSIZE:
 469  470                                  case TIOCGWINSZ:
 470  471                                          mioc2ack(mp, NULL, 0, 0);
 471  472                                          qreply(q, mp);
 472  473                                          break;
 473  474  
 474  475                                  default:
 475  476                                          freemsg(mp);
 476  477                          }
 477  478                          break;
 478  479  
 479  480                  case M_FLUSH:
 480  481                          if (*mp->b_rptr & FLUSHW) {
 481  482                                  if ((ntp->state & IS_PTSTTY) &&
 482  483                                      (*mp->b_rptr & FLUSHBAND))
 483  484                                          flushband(q, *(mp->b_rptr + 1),
 484  485                                              FLUSHDATA);
 485  486                                  else
 486  487                                          flushq(q, FLUSHDATA);
 487  488                          }
 488  489                          putnext(q, mp);
 489  490                          break;
 490  491  
 491  492                  case M_READ:
 492  493                          freemsg(mp);
 493  494                          break;
 494  495  
 495  496                  case M_STOP:
 496  497                          /*
 497  498                           * Set the output flow control state.
 498  499                           */
 499  500                          ntp->state |= OFLOW_CTL;
 500  501                          putnext(q, mp);
 501  502                          break;
 502  503  
 503  504                  case M_START:
 504  505                          /*
 505  506                           * Relieve the output flow control state.
 506  507                           */
 507  508                          ntp->state &= ~OFLOW_CTL;
 508  509                          putnext(q, mp);
 509  510                          qenable(q);
 510  511                          break;
 511  512                  default:
 512  513                          putnext(q, mp);
 513  514                          break;
 514  515                  }
 515  516                  return;
 516  517          }
 517  518          /*
 518  519           * If our queue is nonempty or flow control persists
 519  520           * downstream or module in stopped state, queue this message.
 520  521           */
 521  522          if (q->q_first != NULL || !bcanputnext(q, mp->b_band)) {
 522  523                  /*
 523  524                   * Exception: ioctls, except for those defined to
 524  525                   * take effect after output has drained, should be
 525  526                   * processed immediately.
 526  527                   */
 527  528                  switch (type) {
 528  529  
 529  530                  case M_IOCTL:
 530  531                          iocp = (struct iocblk *)mp->b_rptr;
 531  532                          switch (iocp->ioc_cmd) {
 532  533                          /*
 533  534                           * Queue these.
 534  535                           */
 535  536                          case TCSETSW:
 536  537                          case TCSETSF:
 537  538                          case TCSETAW:
 538  539                          case TCSETAF:
 539  540                          case TCSBRK:
 540  541                                  break;
 541  542  
 542  543                          /*
 543  544                           * Handle all others immediately.
 544  545                           */
 545  546                          default:
 546  547                                  (void) ptemwmsg(q, mp);
 547  548                                  return;
 548  549                          }
 549  550                          break;
 550  551  
 551  552                  case M_DELAY: /* tty delays not supported */
 552  553                          freemsg(mp);
 553  554                          return;
 554  555  
 555  556                  case M_DATA:
 556  557                          if ((mp->b_wptr - mp->b_rptr) < 0) {
 557  558                                  /*
 558  559                                   * Free all bad length messages.
 559  560                                   */
 560  561                                  freemsg(mp);
 561  562                                  return;
 562  563                          } else if ((mp->b_wptr - mp->b_rptr) == 0) {
 563  564                                  if (!(ntp->state & IS_PTSTTY)) {
 564  565                                          freemsg(mp);
 565  566                                          return;
 566  567                                  }
 567  568                          }
 568  569                  }
 569  570                  (void) putq(q, mp);
 570  571                  return;
 571  572          }
 572  573          /*
 573  574           * fast path into ptemwmsg to dispose of mp.
 574  575           */
 575  576          if (!ptemwmsg(q, mp))
 576  577                  (void) putq(q, mp);
 577  578  }
 578  579  
 579  580  /*
 580  581   * ptem write queue service procedure.
 581  582   */
 582  583  static void
 583  584  ptemwsrv(queue_t *q)
 584  585  {
 585  586          mblk_t *mp;
 586  587  
 587  588          while ((mp = getq(q)) != NULL) {
 588  589                  if (!bcanputnext(q, mp->b_band) || !ptemwmsg(q, mp)) {
 589  590                          (void) putbq(q, mp);
 590  591                          break;
 591  592                  }
 592  593          }
 593  594  }
 594  595  
 595  596  
 596  597  /*
 597  598   * This routine is called from both ptemwput and ptemwsrv to do the
 598  599   * actual work of dealing with mp.  ptmewput will have already
 599  600   * dealt with high priority messages.
 600  601   *
 601  602   * Return 1 if the message was processed completely and 0 if not.
 602  603   */
 603  604  static int
 604  605  ptemwmsg(queue_t *q, mblk_t *mp)
 605  606  {
 606  607          struct ptem *ntp = (struct ptem *)q->q_ptr;
 607  608          struct iocblk *iocp;    /* outgoing ioctl structure */
 608  609          struct termio *termiop;
 609  610          struct termios *termiosp;
 610  611          mblk_t *dack_ptr;               /* disconnect message ACK block */
 611  612          mblk_t *pckt_msgp;              /* message sent to the PCKT module */
 612  613          mblk_t *dp;                     /* ioctl reply data */
 613  614          tcflag_t cflags;
 614  615          int error;
 615  616  
 616  617          switch (mp->b_datap->db_type) {
 617  618  
 618  619          case M_IOCTL:
 619  620                  /*
 620  621                   * Note:  for each "set" type operation a copy
 621  622                   * of the M_IOCTL message is made and passed
 622  623                   * downstream.  Eventually the PCKT module, if
 623  624                   * it has been pushed, should pick up this message.
 624  625                   * If the PCKT module has not been pushed the master
 625  626                   * side stream head will free it.
 626  627                   */
 627  628                  iocp = (struct iocblk *)mp->b_rptr;
 628  629                  switch (iocp->ioc_cmd) {
 629  630  
 630  631                  case TCSETAF:
 631  632                  case TCSETSF:
 632  633                          /*
 633  634                           * Flush the read queue.
 634  635                           */
 635  636                          if (putnextctl1(q, M_FLUSH, FLUSHR) == 0) {
 636  637                                  miocnak(q, mp, 0, EAGAIN);
 637  638                                  break;
 638  639                          }
 639  640                          /* FALLTHROUGH */
 640  641  
 641  642                  case TCSETA:
 642  643                  case TCSETAW:
 643  644                  case TCSETS:
 644  645                  case TCSETSW:
 645  646  
 646  647                          switch (iocp->ioc_cmd) {
 647  648                          case TCSETAF:
 648  649                          case TCSETA:
 649  650                          case TCSETAW:
 650  651                                  error = miocpullup(mp, sizeof (struct termio));
 651  652                                  if (error != 0) {
 652  653                                          miocnak(q, mp, 0, error);
 653  654                                          goto out;
 654  655                                  }
 655  656                                  cflags = ((struct termio *)
 656  657                                      mp->b_cont->b_rptr)->c_cflag;
 657  658                                  ntp->cflags =
 658  659                                      (ntp->cflags & 0xffff0000 | cflags);
 659  660                                  break;
 660  661  
 661  662                          case TCSETSF:
 662  663                          case TCSETS:
 663  664                          case TCSETSW:
 664  665                                  error = miocpullup(mp, sizeof (struct termios));
 665  666                                  if (error != 0) {
 666  667                                          miocnak(q, mp, 0, error);
 667  668                                          goto out;
 668  669                                  }
 669  670                                  cflags = ((struct termios *)
 670  671                                      mp->b_cont->b_rptr)->c_cflag;
 671  672                                  ntp->cflags = cflags;
 672  673                                  break;
 673  674                          }
 674  675  
 675  676                          if ((cflags & CBAUD) == B0) {
 676  677                                  /*
 677  678                                   * Hang-up: Send a zero length message.
 678  679                                   */
 679  680                                  dack_ptr = ntp->dack_ptr;
 680  681  
 681  682                                  if (dack_ptr) {
 682  683                                          ntp->dack_ptr = NULL;
 683  684                                          /*
 684  685                                           * Send a zero length message
 685  686                                           * downstream.
 686  687                                           */
 687  688                                          putnext(q, dack_ptr);
 688  689                                  }
 689  690                          } else {
 690  691                                  /*
 691  692                                   * Make a copy of this message and pass it on
 692  693                                   * to the PCKT module.
 693  694                                   */
 694  695                                  if ((pckt_msgp = copymsg(mp)) == NULL) {
 695  696                                          miocnak(q, mp, 0, EAGAIN);
 696  697                                          break;
 697  698                                  }
 698  699                                  putnext(q, pckt_msgp);
 699  700                          }
 700  701                          /*
 701  702                           * Send ACK upstream.
 702  703                           */
 703  704                          mioc2ack(mp, NULL, 0, 0);
 704  705                          qreply(q, mp);
 705  706  out:
 706  707                          break;
 707  708  
 708  709                  case TCGETA:
 709  710                          dp = allocb(sizeof (struct termio), BPRI_MED);
 710  711                          if (dp == NULL) {
 711  712                                  miocnak(q, mp, 0, EAGAIN);
 712  713                                  break;
 713  714                          }
 714  715                          termiop = (struct termio *)dp->b_rptr;
 715  716                          termiop->c_cflag = (ushort_t)ntp->cflags;
 716  717                          mioc2ack(mp, dp, sizeof (struct termio), 0);
 717  718                          qreply(q, mp);
 718  719                          break;
 719  720  
 720  721                  case TCGETS:
 721  722                          dp = allocb(sizeof (struct termios), BPRI_MED);
 722  723                          if (dp == NULL) {
 723  724                                  miocnak(q, mp, 0, EAGAIN);
 724  725                                  break;
 725  726                          }
 726  727                          termiosp = (struct termios *)dp->b_rptr;
 727  728                          termiosp->c_cflag = ntp->cflags;
 728  729                          mioc2ack(mp, dp, sizeof (struct termios), 0);
 729  730                          qreply(q, mp);
 730  731                          break;
 731  732  
 732  733                  case TCSBRK:
 733  734                          error = miocpullup(mp, sizeof (int));
 734  735                          if (error != 0) {
 735  736                                  miocnak(q, mp, 0, error);
 736  737                                  break;
 737  738                          }
 738  739  
 739  740                          /*
 740  741                           * Need a copy of this message to pass it on to
 741  742                           * the PCKT module.
 742  743                           */
 743  744                          if ((pckt_msgp = copymsg(mp)) == NULL) {
 744  745                                  miocnak(q, mp, 0, EAGAIN);
 745  746                                  break;
 746  747                          }
 747  748                          /*
 748  749                           * Send a copy of the M_IOCTL to the PCKT module.
 749  750                           */
 750  751                          putnext(q, pckt_msgp);
 751  752  
 752  753                          /*
 753  754                           * TCSBRK meaningful if data part of message is 0
 754  755                           * cf. termio(7).
 755  756                           */
 756  757                          if (!(*(int *)mp->b_cont->b_rptr))
 757  758                                  (void) putnextctl(q, M_BREAK);
 758  759                          /*
 759  760                           * ACK the ioctl.
 760  761                           */
 761  762                          mioc2ack(mp, NULL, 0, 0);
 762  763                          qreply(q, mp);
 763  764                          break;
 764  765  
 765  766                  case JWINSIZE:
 766  767                  case TIOCGWINSZ:
 767  768                  case TIOCSWINSZ:
 768  769                          ptioc(q, mp, WRSIDE);
 769  770                          break;
 770  771  
 771  772                  case TIOCSTI:
 772  773                          /*
 773  774                           * Simulate typing of a character at the terminal.  In
 774  775                           * all cases, we acknowledge the ioctl and pass a copy
 775  776                           * of it along for the PCKT module to encapsulate.  If
 776  777                           * not in remote mode, we also process the ioctl
 777  778                           * itself, looping the character given as its argument
 778  779                           * back around to the read side.
 779  780                           */
 780  781  
 781  782                          /*
 782  783                           * Need a copy of this message to pass on to the PCKT
 783  784                           * module.
 784  785                           */
 785  786                          if ((pckt_msgp = copymsg(mp)) == NULL) {
 786  787                                  miocnak(q, mp, 0, EAGAIN);
 787  788                                  break;
 788  789                          }
 789  790                          if ((ntp->state & REMOTEMODE) == 0) {
 790  791                                  mblk_t *bp;
 791  792  
 792  793                                  error = miocpullup(mp, sizeof (char));
 793  794                                  if (error != 0) {
 794  795                                          freemsg(pckt_msgp);
 795  796                                          miocnak(q, mp, 0, error);
 796  797                                          break;
 797  798                                  }
 798  799  
 799  800                                  /*
 800  801                                   * The permission checking has already been
 801  802                                   * done at the stream head, since it has to be
 802  803                                   * done in the context of the process doing
 803  804                                   * the call.
 804  805                                   */
 805  806                                  if ((bp = allocb(1, BPRI_MED)) == NULL) {
 806  807                                          freemsg(pckt_msgp);
 807  808                                          miocnak(q, mp, 0, EAGAIN);
 808  809                                          break;
 809  810                                  }
 810  811                                  /*
 811  812                                   * XXX: Is EAGAIN really the right response to
 812  813                                   *      flow control blockage?
 813  814                                   */
 814  815                                  if (!bcanputnext(RD(q), mp->b_band)) {
 815  816                                          freemsg(bp);
 816  817                                          freemsg(pckt_msgp);
 817  818                                          miocnak(q, mp, 0, EAGAIN);
 818  819                                          break;
 819  820                                  }
 820  821                                  *bp->b_wptr++ = *mp->b_cont->b_rptr;
 821  822                                  qreply(q, bp);
 822  823                          }
 823  824  
 824  825                          putnext(q, pckt_msgp);
 825  826                          mioc2ack(mp, NULL, 0, 0);
 826  827                          qreply(q, mp);
 827  828                          break;
 828  829  
 829  830                  case PTSSTTY:
 830  831                          if (ntp->state & IS_PTSTTY) {
 831  832                                  miocnak(q, mp, 0, EEXIST);
 832  833                          } else {
 833  834                                  ntp->state |= IS_PTSTTY;
 834  835                                  mioc2ack(mp, NULL, 0, 0);
 835  836                                  qreply(q, mp);
 836  837                          }
 837  838                          break;
 838  839  
 839  840                  default:
 840  841                          /*
 841  842                           * End of the line.  The slave driver doesn't see any
 842  843                           * ioctls that we don't explicitly pass along to it.
 843  844                           */
 844  845                          miocnak(q, mp, 0, EINVAL);
 845  846                          break;
 846  847                  }
 847  848                  break;
 848  849  
 849  850          case M_DELAY: /* tty delays not supported */
 850  851                  freemsg(mp);
 851  852                  break;
 852  853  
 853  854          case M_DATA:
 854  855                  if ((mp->b_wptr - mp->b_rptr) < 0) {
 855  856                          /*
 856  857                           * Free all bad length messages.
 857  858                           */
 858  859                          freemsg(mp);
 859  860                          break;
 860  861                  } else if ((mp->b_wptr - mp->b_rptr) == 0) {
 861  862                          if (!(ntp->state & IS_PTSTTY)) {
 862  863                                  freemsg(mp);
 863  864                                  break;
 864  865                          }
 865  866                  }
 866  867                  if (ntp->state & OFLOW_CTL)
 867  868                          return (0);
 868  869  
 869  870          default:
 870  871                  putnext(q, mp);
 871  872                  break;
 872  873  
 873  874          }
 874  875  
 875  876          return (1);
 876  877  }
 877  878  
 878  879  /*
 879  880   * Message must be of type M_IOCTL or M_IOCDATA for this routine to be called.
 880  881   */
 881  882  static void
 882  883  ptioc(queue_t *q, mblk_t *mp, int qside)
 883  884  {
 884  885          struct ptem *tp;
 885  886          struct iocblk *iocp;
 886  887          struct winsize *wb;
 887  888          struct jwinsize *jwb;
 888  889          mblk_t *tmp;
 889  890          mblk_t *pckt_msgp;      /* message sent to the PCKT module */
 890  891          int error;
 891  892  
 892  893          iocp = (struct iocblk *)mp->b_rptr;
 893  894          tp = (struct ptem *)q->q_ptr;
 894  895  
 895  896          switch (iocp->ioc_cmd) {
 896  897  
 897  898          case JWINSIZE:
 898  899                  /*
 899  900                   * For compatibility:  If all zeros, NAK the message for dumb
 900  901                   * terminals.
 901  902                   */
 902  903                  if ((tp->wsz.ws_row == 0) && (tp->wsz.ws_col == 0) &&
 903  904                      (tp->wsz.ws_xpixel == 0) && (tp->wsz.ws_ypixel == 0)) {
 904  905                          miocnak(q, mp, 0, EINVAL);
 905  906                          return;
 906  907                  }
 907  908  
 908  909                  tmp = allocb(sizeof (struct jwinsize), BPRI_MED);
 909  910                  if (tmp == NULL) {
 910  911                          miocnak(q, mp, 0, EAGAIN);
 911  912                          return;
 912  913                  }
 913  914  
 914  915                  if (iocp->ioc_count == TRANSPARENT)
 915  916                          mcopyout(mp, NULL, sizeof (struct jwinsize), NULL, tmp);
 916  917                  else
 917  918                          mioc2ack(mp, tmp, sizeof (struct jwinsize), 0);
 918  919  
 919  920                  jwb = (struct jwinsize *)mp->b_cont->b_rptr;
 920  921                  jwb->bytesx = tp->wsz.ws_col;
 921  922                  jwb->bytesy = tp->wsz.ws_row;
 922  923                  jwb->bitsx = tp->wsz.ws_xpixel;
 923  924                  jwb->bitsy = tp->wsz.ws_ypixel;
 924  925  
 925  926                  qreply(q, mp);
 926  927                  return;
 927  928  
 928  929          case TIOCGWINSZ:
 929  930                  /*
 930  931                   * If all zeros NAK the message for dumb terminals.
 931  932                   */
 932  933                  if ((tp->wsz.ws_row == 0) && (tp->wsz.ws_col == 0) &&
 933  934                      (tp->wsz.ws_xpixel == 0) && (tp->wsz.ws_ypixel == 0)) {
 934  935                          miocnak(q, mp, 0, EINVAL);
 935  936                          return;
 936  937                  }
 937  938  
 938  939                  tmp = allocb(sizeof (struct winsize), BPRI_MED);
 939  940                  if (tmp == NULL) {
 940  941                          miocnak(q, mp, 0, EAGAIN);
 941  942                          return;
 942  943                  }
 943  944  
 944  945                  mioc2ack(mp, tmp, sizeof (struct winsize), 0);
 945  946  
 946  947                  wb = (struct winsize *)mp->b_cont->b_rptr;
 947  948                  wb->ws_row = tp->wsz.ws_row;
 948  949                  wb->ws_col = tp->wsz.ws_col;
 949  950                  wb->ws_xpixel = tp->wsz.ws_xpixel;
 950  951                  wb->ws_ypixel = tp->wsz.ws_ypixel;
 951  952  
 952  953                  qreply(q, mp);
 953  954                  return;
 954  955  
 955  956          case TIOCSWINSZ:
 956  957                  error = miocpullup(mp, sizeof (struct winsize));
 957  958                  if (error != 0) {
 958  959                          miocnak(q, mp, 0, error);
 959  960                          return;
 960  961                  }
 961  962  
 962  963                  wb = (struct winsize *)mp->b_cont->b_rptr;
 963  964                  /*
 964  965                   * Send a SIGWINCH signal if the row/col information has
 965  966                   * changed.
 966  967                   */
 967  968                  if ((tp->wsz.ws_row != wb->ws_row) ||
 968  969                      (tp->wsz.ws_col != wb->ws_col) ||
 969  970                      (tp->wsz.ws_xpixel != wb->ws_xpixel) ||
 970  971                      (tp->wsz.ws_ypixel != wb->ws_xpixel)) {
 971  972                          /*
 972  973                           * SIGWINCH is always sent upstream.
 973  974                           */
 974  975                          if (qside == WRSIDE)
 975  976                                  (void) putnextctl1(RD(q), M_SIG, SIGWINCH);
 976  977                          else if (qside == RDSIDE)
 977  978                                  (void) putnextctl1(q, M_SIG, SIGWINCH);
 978  979                          /*
 979  980                           * Message may have come in as an M_IOCDATA; pass it
 980  981                           * to the master side as an M_IOCTL.
 981  982                           */
 982  983                          mp->b_datap->db_type = M_IOCTL;
 983  984                          if (qside == WRSIDE) {
 984  985                                  /*
 985  986                                   * Need a copy of this message to pass on to
 986  987                                   * the PCKT module, only if the M_IOCTL
 987  988                                   * orginated from the slave side.
 988  989                                   */
 989  990                                  if ((pckt_msgp = copymsg(mp)) == NULL) {
 990  991                                          miocnak(q, mp, 0, EAGAIN);
 991  992                                          return;
 992  993                                  }
 993  994                                  putnext(q, pckt_msgp);
 994  995                          }
 995  996                          tp->wsz.ws_row = wb->ws_row;
 996  997                          tp->wsz.ws_col = wb->ws_col;
 997  998                          tp->wsz.ws_xpixel = wb->ws_xpixel;
 998  999                          tp->wsz.ws_ypixel = wb->ws_ypixel;
 999 1000                  }
1000 1001  
1001 1002                  mioc2ack(mp, NULL, 0, 0);
1002 1003                  qreply(q, mp);
1003 1004                  return;
1004 1005  
1005 1006          case TIOCSIGNAL: {
1006 1007                  /*
1007 1008                   * This ioctl can emanate from the master side in remote
1008 1009                   * mode only.
1009 1010                   */
1010 1011                  int     sig;
1011 1012  
1012 1013                  if (DB_TYPE(mp) == M_IOCTL && iocp->ioc_count != TRANSPARENT) {
1013 1014                          error = miocpullup(mp, sizeof (int));
1014 1015                          if (error != 0) {
1015 1016                                  miocnak(q, mp, 0, error);
1016 1017                                  return;
1017 1018                          }
1018 1019                  }
1019 1020  
1020 1021                  if (DB_TYPE(mp) == M_IOCDATA || iocp->ioc_count != TRANSPARENT)
1021 1022                          sig = *(int *)mp->b_cont->b_rptr;
1022 1023                  else
1023 1024                          sig = (int)*(intptr_t *)mp->b_cont->b_rptr;
1024 1025  
1025 1026                  if (sig < 1 || sig >= NSIG) {
1026 1027                          miocnak(q, mp, 0, EINVAL);
1027 1028                          return;
1028 1029                  }
1029 1030  
1030 1031                  /*
1031 1032                   * Send an M_PCSIG message up the slave's read side and
1032 1033                   * respond back to the master with an ACK or NAK as
1033 1034                   * appropriate.
1034 1035                   */
1035 1036                  if (putnextctl1(q, M_PCSIG, sig) == 0) {
1036 1037                          miocnak(q, mp, 0, EAGAIN);
1037 1038                          return;
1038 1039                  }
1039 1040  
1040 1041                  mioc2ack(mp, NULL, 0, 0);
1041 1042                  qreply(q, mp);
1042 1043                  return;
1043 1044          }
1044 1045  
1045 1046          case TIOCREMOTE: {
1046 1047                  int     onoff;
1047 1048                  mblk_t  *mctlp;
1048 1049  
1049 1050                  if (DB_TYPE(mp) == M_IOCTL) {
1050 1051                          error = miocpullup(mp, sizeof (int));
1051 1052                          if (error != 0) {
1052 1053                                  miocnak(q, mp, 0, error);
1053 1054                                  return;
1054 1055                          }
1055 1056                  }
1056 1057  
1057 1058                  onoff = *(int *)mp->b_cont->b_rptr;
1058 1059  
1059 1060                  /*
1060 1061                   * Send M_CTL up using the iocblk format.
1061 1062                   */
1062 1063                  mctlp = mkiocb(onoff ? MC_NO_CANON : MC_DO_CANON);
1063 1064                  if (mctlp == NULL) {
1064 1065                          miocnak(q, mp, 0, EAGAIN);
1065 1066                          return;
1066 1067                  }
1067 1068                  mctlp->b_datap->db_type = M_CTL;
1068 1069                  putnext(q, mctlp);
1069 1070  
1070 1071                  /*
1071 1072                   * ACK the ioctl.
1072 1073                   */
1073 1074                  mioc2ack(mp, NULL, 0, 0);
1074 1075                  qreply(q, mp);
1075 1076  
1076 1077                  /*
1077 1078                   * Record state change.
1078 1079                   */
1079 1080                  if (onoff)
1080 1081                          tp->state |= REMOTEMODE;
1081 1082                  else
1082 1083                          tp->state &= ~REMOTEMODE;
1083 1084                  return;
1084 1085          }
1085 1086  
1086 1087          default:
1087 1088                  putnext(q, mp);
1088 1089                  return;
1089 1090          }
1090 1091  }
  
    | 
      ↓ open down ↓ | 
    1015 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX