Print this page
    
MFV: illumos-gate@39cc040ff7c0c62aae858381f21d0567dd60042e
9967 dflt_termios and base_termios need update
Reviewed by: Andy Fiddaman <omnios@citrus-it.net>
Reviewed by: Jason King <jason.king@joyent.com>
Approved by: Dan McDonald <danmcd@joyent.com>
Author: Toomas Soome <tsoome@me.com>
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/ttcompat.c
          +++ new/usr/src/uts/common/io/ttcompat.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
  
    | 
      ↓ open down ↓ | 
    13 lines elided | 
    
      ↑ open up ↑ | 
  
  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 2009 Sun Microsystems, Inc.  All rights reserved.
  23   23   * Use is subject to license terms.
       24 + * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
  24   25   */
  25   26  
  26   27  /*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
  27   28  /*        All Rights Reserved   */
  28   29  
  29   30  /*
  30   31   * University Copyright- Copyright (c) 1982, 1986, 1988
  31   32   * The Regents of the University of California
  32   33   * All Rights Reserved
  33   34   *
  34   35   * University Acknowledgment- Portions of this document are derived from
  35   36   * software developed by the University of California, Berkeley, and its
  36   37   * contributors.
  37   38   */
  38   39  
  39   40  /*
  40   41   * Module to intercept old V7 and 4BSD "ioctl" calls.
  41   42   */
  42   43  
  43   44  #include <sys/types.h>
  44   45  #include <sys/param.h>
  45   46  #include <sys/signal.h>
  46   47  #include <sys/file.h>
  47   48  #include <sys/termios.h>
  48   49  #include <sys/ttold.h>
  49   50  #include <sys/cmn_err.h>
  50   51  #include <sys/stream.h>
  51   52  #include <sys/stropts.h>
  52   53  #include <sys/strsubr.h>
  53   54  #include <sys/strsun.h>
  54   55  #include <sys/errno.h>
  55   56  #include <sys/debug.h>
  56   57  #include <sys/ttcompat.h>
  57   58  #include <sys/ddi.h>
  58   59  #include <sys/sunddi.h>
  59   60  #include <sys/kmem.h>
  60   61  #include <sys/policy.h>
  61   62  
  62   63  /*
  63   64   * This is the loadable module wrapper.
  64   65   */
  65   66  #include <sys/conf.h>
  
    | 
      ↓ open down ↓ | 
    32 lines elided | 
    
      ↑ open up ↑ | 
  
  66   67  #include <sys/modctl.h>
  67   68  
  68   69  /* See os/streamio.c */
  69   70  extern int sgttyb_handling;
  70   71  
  71   72  static struct streamtab ttcoinfo;
  72   73  
  73   74  static struct fmodsw fsw = {
  74   75          "ttcompat",
  75   76          &ttcoinfo,
  76      -        D_MTQPAIR | D_MP
       77 +        D_MTQPAIR | D_MP | _D_SINGLE_INSTANCE
  77   78  };
  78   79  
  79   80  /*
  80   81   * Module linkage information for the kernel.
  81   82   */
  82   83  
  83   84  static struct modlstrmod modlstrmod = {
  84   85          &mod_strmodops,
  85   86          "alt ioctl calls",
  86   87          &fsw
  87   88  };
  88   89  
  89   90  static struct modlinkage modlinkage = {
  90   91          MODREV_1, &modlstrmod, NULL
  91   92  };
  92   93  
  93   94  int
  94   95  _init(void)
  95   96  {
  96   97          return (mod_install(&modlinkage));
  97   98  }
  98   99  
  99  100  int
 100  101  _fini(void)
 101  102  {
 102  103          return (mod_remove(&modlinkage));
 103  104  }
 104  105  
 105  106  int
 106  107  _info(struct modinfo *modinfop)
 107  108  {
 108  109          return (mod_info(&modlinkage, modinfop));
 109  110  }
 110  111  
 111  112  static int ttcompatopen(queue_t *, dev_t *, int, int, cred_t *);
 112  113  static int ttcompatclose(queue_t *, int, cred_t *);
 113  114  static void ttcompatrput(queue_t *, mblk_t *);
 114  115  static void ttcompatwput(queue_t *, mblk_t *);
 115  116  
 116  117  static struct module_info ttycompatmiinfo = {
 117  118          0,
 118  119          "ttcompat",
 119  120          0,
 120  121          INFPSZ,
 121  122          2048,
 122  123          128
 123  124  };
 124  125  
 125  126  static struct qinit ttycompatrinit = {
 126  127          (int (*)())ttcompatrput,
 127  128          NULL,
 128  129          ttcompatopen,
 129  130          ttcompatclose,
 130  131          NULL,
 131  132          &ttycompatmiinfo
 132  133  };
 133  134  
 134  135  static struct module_info ttycompatmoinfo = {
 135  136          42,
 136  137          "ttcompat",
 137  138          0,
 138  139          INFPSZ,
 139  140          300,
 140  141          200
 141  142  };
 142  143  
 143  144  static struct qinit ttycompatwinit = {
 144  145          (int (*)())ttcompatwput,
 145  146          NULL,
 146  147          ttcompatopen,
 147  148          ttcompatclose,
 148  149          NULL,
  
    | 
      ↓ open down ↓ | 
    62 lines elided | 
    
      ↑ open up ↑ | 
  
 149  150          &ttycompatmoinfo
 150  151  };
 151  152  
 152  153  static struct streamtab ttcoinfo = {
 153  154          &ttycompatrinit,
 154  155          &ttycompatwinit,
 155  156          NULL,
 156  157          NULL
 157  158  };
 158  159  
 159      -/*
 160      - * This is the termios structure that is used to reset terminal settings
 161      - * when the underlying device is an instance of zcons.  It came from
 162      - * cmd/init/init.c and should be kept in-sync with dflt_termios found therein.
 163      - */
 164      -static const struct termios base_termios = {
 165      -        BRKINT|ICRNL|IXON|IMAXBEL,                              /* iflag */
 166      -        OPOST|ONLCR|TAB3,                                       /* oflag */
 167      -        CS8|CREAD|B9600,                                        /* cflag */
 168      -        ISIG|ICANON|ECHO|ECHOE|ECHOK|ECHOCTL|ECHOKE|IEXTEN,     /* lflag */
 169      -        CINTR, CQUIT, CERASE, CKILL, CEOF, 0, 0, 0, 0, 0, 0, 0, /* c_cc vals */
 170      -        0, 0, 0, 0, 0, 0, 0
 171      -};
 172      -
 173      -
 174  160  static void ttcompat_do_ioctl(ttcompat_state_t *, queue_t *, mblk_t *);
 175  161  static void ttcompat_ioctl_ack(queue_t *, mblk_t *);
 176  162  static void ttcopyout(queue_t *, mblk_t *);
 177  163  static void ttcompat_ioctl_nak(queue_t *, mblk_t *);
 178  164  static void from_compat(compat_state_t *, struct termios *);
 179  165  static void to_compat(struct termios *, compat_state_t *);
 180  166  
 181  167  /*
 182  168   * Open - get the current modes and translate them to the V7/4BSD equivalent.
 183  169   */
 184  170  /*ARGSUSED*/
 185  171  static int
 186  172  ttcompatopen(queue_t *q, dev_t *devp, int oflag, int sflag, cred_t *crp)
 187  173  {
 188  174          ttcompat_state_t *tp;
 189      -        mblk_t *mp;
 190      -        mblk_t *datamp;
 191      -        struct iocblk *iocb;
 192      -        int error;
 193  175  
 194  176          if (q->q_ptr != NULL)  {
 195  177                  tp = (ttcompat_state_t *)q->q_ptr;
 196  178                  /* fail open if TIOCEXCL was done and its not privileged */
 197  179                  if ((tp->t_new_lflags & XCLUDE) &&
 198  180                      secpolicy_excl_open(crp) != 0) {
 199  181                          return (EBUSY);
 200  182                  }
 201  183                  return (0);             /* already attached */
 202  184          }
 203  185          tp = kmem_zalloc(sizeof (ttcompat_state_t), KM_SLEEP);
 204      -        tp->t_iocpending = NULL;
 205      -        tp->t_state = 0;
 206      -        tp->t_iocid = 0;
 207      -        tp->t_ioccmd = 0;
 208      -        tp->t_new_lflags = 0;
 209      -        tp->t_curstate.t_flags = 0;
 210      -        tp->t_curstate.t_ispeed = B0;
 211      -        tp->t_curstate.t_ospeed = B0;
 212      -        tp->t_curstate.t_erase = '\0';
 213      -        tp->t_curstate.t_kill = '\0';
 214      -        tp->t_curstate.t_intrc = '\0';
 215      -        tp->t_curstate.t_quitc = '\0';
 216      -        tp->t_curstate.t_startc = '\0';
 217      -        tp->t_curstate.t_stopc = '\0';
 218      -        tp->t_curstate.t_eofc = '\0';
 219      -        tp->t_curstate.t_brkc = '\0';
 220      -        tp->t_curstate.t_suspc = '\0';
 221      -        tp->t_curstate.t_dsuspc = '\0';
 222      -        tp->t_curstate.t_rprntc = '\0';
 223      -        tp->t_curstate.t_flushc = '\0';
 224      -        tp->t_curstate.t_werasc = '\0';
 225      -        tp->t_curstate.t_lnextc = '\0';
 226      -        tp->t_curstate.t_xflags = 0;
 227      -        tp->t_bufcallid = 0;
 228      -        tp->t_arg = 0;
 229      -
 230  186          q->q_ptr = tp;
 231  187          WR(q)->q_ptr = tp;
 232  188          qprocson(q);
 233  189  
 234      -        /*
 235      -         * Determine if the underlying device is a zcons instance.  If so,
 236      -         * then issue a termios ioctl to reset the terminal settings.
 237      -         */
 238      -        if (getmajor(q->q_stream->sd_vnode->v_rdev) !=
 239      -            ddi_name_to_major("zcons"))
 240      -                return (0);
 241      -
 242      -        /*
 243      -         * Create the ioctl message.
 244      -         */
 245      -        if ((mp = mkiocb(TCSETSF)) == NULL) {
 246      -                error = ENOMEM;
 247      -                goto common_error;
 248      -        }
 249      -        if ((datamp = allocb(sizeof (struct termios), BPRI_HI)) == NULL) {
 250      -                freemsg(mp);
 251      -                error = ENOMEM;
 252      -                goto common_error;
 253      -        }
 254      -        iocb = (struct iocblk *)mp->b_rptr;
 255      -        iocb->ioc_count = sizeof (struct termios);
 256      -        bcopy(&base_termios, datamp->b_rptr, sizeof (struct termios));
 257      -        datamp->b_wptr += sizeof (struct termios);
 258      -        mp->b_cont = datamp;
 259      -
 260      -        /*
 261      -         * Send the ioctl message on its merry way toward the driver.
 262      -         * Set some state beforehand so we can properly wait for
 263      -         * an acknowledgement.
 264      -         */
 265      -        tp->t_state |= TS_IOCWAIT | TS_TIOCNAK;
 266      -        tp->t_iocid = iocb->ioc_id;
 267      -        tp->t_ioccmd = TCSETSF;
 268      -        putnext(WR(q), mp);
 269      -
 270      -        /*
 271      -         * Wait for an acknowledgement.  A NAK is treated as an error.
 272      -         * The presence of the TS_TIOCNAK flag indicates that a NAK was
 273      -         * received.
 274      -         */
 275      -        while (tp->t_state & TS_IOCWAIT) {
 276      -                if (qwait_sig(q) == 0) {
 277      -                        error = EINTR;
 278      -                        goto common_error;
 279      -                }
 280      -        }
 281      -        if (!(tp->t_state & TS_TIOCNAK))
 282      -                return (0);
 283      -        error = ENOTTY;
 284      -
 285      -common_error:
 286      -        qprocsoff(q);
 287      -        kmem_free(tp, sizeof (ttcompat_state_t));
 288      -        q->q_ptr = NULL;
 289      -        WR(q)->q_ptr = NULL;
 290      -        return (error);
      190 +        return (0);
 291  191  }
 292  192  
 293  193  /* ARGSUSED1 */
 294  194  static int
 295  195  ttcompatclose(queue_t *q, int flag, cred_t *crp)
 296  196  {
 297  197          ttcompat_state_t *tp = (ttcompat_state_t *)q->q_ptr;
 298  198          mblk_t *mp;
 299  199  
 300  200          /* Dump the state structure, then unlink it */
 301  201          qprocsoff(q);
 302  202          if (tp->t_bufcallid != 0) {
 303  203                  qunbufcall(q, tp->t_bufcallid);
 304  204                  tp->t_bufcallid = 0;
 305  205          }
 306  206          if ((mp = tp->t_iocpending) != NULL)
 307  207                  freemsg(mp);
 308  208          kmem_free(tp, sizeof (ttcompat_state_t));
 309  209          q->q_ptr = NULL;
 310  210  
 311  211          return (0);
 312  212  }
 313  213  
 314  214  /*
 315  215   * Put procedure for input from driver end of stream (read queue).
 316  216   * Most messages just get passed to the next guy up; we intercept
 317  217   * "ioctl" replies, and if it's an "ioctl" whose reply we plan to do
 318  218   * something with, we do it.
 319  219   */
 320  220  static void
 321  221  ttcompatrput(queue_t *q, mblk_t *mp)
 322  222  {
 323  223          switch (mp->b_datap->db_type) {
 324  224  
 325  225          case M_IOCACK:
 326  226                  ttcompat_ioctl_ack(q, mp);
 327  227                  break;
 328  228  
 329  229          case M_IOCNAK:
 330  230                  ttcompat_ioctl_nak(q, mp);
 331  231                  break;
 332  232  
 333  233          default:
 334  234                  putnext(q, mp);
 335  235                  break;
 336  236          }
 337  237  }
 338  238  
 339  239  /*
 340  240   * Line discipline output queue put procedure: speeds M_IOCTL
 341  241   * messages.
 342  242   */
 343  243  static void
 344  244  ttcompatwput(queue_t *q, mblk_t *mp)
 345  245  {
 346  246          ttcompat_state_t *tp;
 347  247          struct copyreq *cqp;
 348  248          struct copyresp *csp;
 349  249          struct iocblk *iocbp;
 350  250  
 351  251          tp = (ttcompat_state_t *)q->q_ptr;
 352  252  
 353  253          /*
 354  254           * Process some M_IOCTL messages here; pass everything else down.
 355  255           */
 356  256          switch (mp->b_datap->db_type) {
 357  257  
 358  258          default:
 359  259                  putnext(q, mp);
 360  260                  return;
 361  261  
 362  262          case M_IOCTL:
 363  263                  iocbp = (struct iocblk *)mp->b_rptr;
 364  264  
 365  265                  switch (iocbp->ioc_cmd) {
 366  266  
 367  267                  default:
 368  268          /* these are ioctls with no arguments or are known to stream head */
 369  269          /* process them right away */
 370  270                          ttcompat_do_ioctl(tp, q, mp);
 371  271                          return;
 372  272                  case TIOCSETN:
 373  273                  case TIOCSLTC:
 374  274                  case TIOCSETC:
 375  275                  case TIOCLBIS:
 376  276                  case TIOCLBIC:
 377  277                  case TIOCLSET:
 378  278                  case TIOCFLUSH:
 379  279                          if (iocbp->ioc_count != TRANSPARENT) {
 380  280                                  putnext(q, mp);
 381  281                                  return;
 382  282                          }
 383  283  
 384  284                          mp->b_datap->db_type = M_COPYIN;
 385  285                          cqp = (struct copyreq *)mp->b_rptr;
 386  286                          cqp->cq_addr = (caddr_t)*(intptr_t *)mp->b_cont->b_rptr;
 387  287                          switch (iocbp->ioc_cmd) {
 388  288                                  case TIOCSETN:
 389  289                                          cqp->cq_size = sizeof (struct sgttyb);
 390  290                                          break;
 391  291                                  case TIOCSLTC:
 392  292                                          cqp->cq_size = sizeof (struct ltchars);
 393  293                                          break;
 394  294                                  case TIOCSETC:
 395  295                                          cqp->cq_size = sizeof (struct tchars);
 396  296                                          break;
 397  297                                  case TIOCLBIS:
 398  298                                  case TIOCLBIC:
 399  299                                  case TIOCLSET:
 400  300                                  case TIOCFLUSH:
 401  301                                          cqp->cq_size = sizeof (int);
 402  302                                          break;
 403  303                                  default:
 404  304                                          break;
 405  305                          }
 406  306                          cqp->cq_flag = 0;
 407  307                          cqp->cq_private = NULL;
 408  308                          freemsg(mp->b_cont);
 409  309                          mp->b_cont = NULL;
 410  310                          mp->b_wptr = mp->b_rptr + sizeof (struct copyreq);
 411  311                          tp->t_ioccmd = iocbp->ioc_cmd;
 412  312                          tp->t_state |= TS_W_IN;
 413  313                          qreply(q, mp);
 414  314                          return;
 415  315  
 416  316                  } /* switch ioc_cmd */
 417  317          case M_IOCDATA:
 418  318                  csp = (struct copyresp *)mp->b_rptr;
 419  319  
 420  320                  switch (csp->cp_cmd) {
 421  321  
 422  322                  default:
 423  323                          putnext(q, mp);
 424  324                          return;
 425  325  
 426  326                  case TIOCSETN:
 427  327                  case TIOCSLTC:
 428  328                  case TIOCSETC:
 429  329                  case TIOCLBIS:
 430  330                  case TIOCLBIC:
 431  331                  case TIOCLSET:
 432  332                  case TIOCFLUSH:
 433  333                          tp->t_state &= ~TS_W_IN;
 434  334                          if (csp->cp_rval != 0) {        /* failure */
 435  335                                  freemsg(mp);
 436  336                                  return;
 437  337                          }
 438  338  
 439  339                          /* make it look like an ioctl */
 440  340                          mp->b_datap->db_type = M_IOCTL;
 441  341                          mp->b_wptr = mp->b_rptr + sizeof (struct iocblk);
 442  342                          iocbp = (struct iocblk *)mp->b_rptr;
 443  343                          iocbp->ioc_count = MBLKL(mp->b_cont);
 444  344                          iocbp->ioc_error = 0;
 445  345                          iocbp->ioc_rval = 0;
 446  346                          ttcompat_do_ioctl(tp, q, mp);
 447  347                          return;
 448  348  
 449  349                  case TIOCGLTC:
 450  350                  case TIOCLGET:
 451  351                  case TIOCGETC:
 452  352                          tp->t_state &= ~TS_W_OUT;
 453  353                          if (csp->cp_rval != 0) {        /* failure */
 454  354                                  freemsg(mp);
 455  355                                  return;
 456  356                          }
 457  357  
 458  358                          iocbp = (struct iocblk *)mp->b_rptr;
 459  359                          iocbp->ioc_count = 0;
 460  360                          iocbp->ioc_error = 0;
 461  361                          iocbp->ioc_rval = 0;
 462  362                          mp->b_datap->db_type = M_IOCACK;
 463  363                          qreply(q, mp);
 464  364                          return;
 465  365  
 466  366                  } /* switch cp_cmd */
 467  367          } /* end message switch */
 468  368  }
 469  369  
 470  370  /*
 471  371   * Retry an "ioctl", now that "bufcall" claims we may be able to allocate
 472  372   * the buffer we need.
 473  373   */
 474  374  static void
 475  375  ttcompat_reioctl(void *arg)
 476  376  {
 477  377          queue_t *q = arg;
 478  378          ttcompat_state_t *tp;
 479  379          mblk_t *mp;
 480  380  
 481  381          tp = (ttcompat_state_t *)q->q_ptr;
 482  382          tp->t_bufcallid = 0;
 483  383  
 484  384          if ((mp = tp->t_iocpending) != NULL) {
 485  385                  tp->t_iocpending = NULL;        /* not pending any more */
 486  386                  ttcompat_do_ioctl(tp, q, mp);
 487  387          }
 488  388  }
 489  389  
 490  390  /*
 491  391   * Handle old-style "ioctl" messages; pass the rest down unmolested.
 492  392   */
 493  393  static void
 494  394  ttcompat_do_ioctl(ttcompat_state_t *tp, queue_t *q, mblk_t *mp)
 495  395  {
 496  396          struct iocblk *iocp;
 497  397          int error;
 498  398  
 499  399          /*
 500  400           * Most of the miocpullup()'s below aren't needed because the
 501  401           * ioctls in question are actually transparent M_IOCDATA messages
 502  402           * dummied to look like M_IOCTL messages.  However, for clarity and
 503  403           * robustness against future changes, we've included them anyway.
 504  404           */
 505  405  
 506  406          iocp = (struct iocblk *)mp->b_rptr;
 507  407          switch (iocp->ioc_cmd) {
 508  408  
 509  409          /*
 510  410           * "get"-style calls that get translated data from the "termios"
 511  411           * structure.  Save the existing code and pass it down as a TCGETS.
 512  412           */
 513  413          case TIOCGETC:
 514  414          case TIOCLGET:
 515  415          case TIOCGLTC:
 516  416                  if (iocp->ioc_count != TRANSPARENT) {
 517  417                          miocnak(q, mp, 0, EINVAL);
 518  418                          return;
 519  419                  }
 520  420  
 521  421                  /*
 522  422                   * We can get here with t_arg != 0, iff the stream head
 523  423                   * has for some reason given up on the ioctl in progress.
 524  424                   * The most likely cause is an interrupted ioctl syscall.
 525  425                   * We will behave robustly because (given our perimeter)
 526  426                   * the ttcompat_state_t will get set up for the new ioctl,
 527  427                   * and when the response we were waiting for appears it
 528  428                   * will be passed on to the stream head which will discard
 529  429                   * it as non-current.
 530  430                   */
 531  431                  ASSERT(mp->b_cont != NULL);
 532  432                  tp->t_arg = *(intptr_t *)mp->b_cont->b_rptr;
 533  433                  /* free the data buffer - it might not be sufficient */
 534  434                  /* driver will allocate one for termios size */
 535  435                  freemsg(mp->b_cont);
 536  436                  mp->b_cont = NULL;
 537  437                  iocp->ioc_count = 0;
 538  438                  /* FALLTHRU */
 539  439          case TIOCGETP:
 540  440                  goto dogets;
 541  441  
 542  442          /*
 543  443           * "set"-style calls that set translated data into a "termios"
 544  444           * structure.  Set our idea of the new state from the value
 545  445           * given to us.  We then have to get the current state, so we
 546  446           * turn this guy into a TCGETS and pass it down.  When the
 547  447           * ACK comes back, we modify the state we got back and shove it
 548  448           * back down as the appropriate type of TCSETS.
 549  449           */
 550  450          case TIOCSETP:
 551  451          case TIOCSETN:
 552  452                  error = miocpullup(mp, sizeof (struct sgttyb));
 553  453                  if (error != 0) {
 554  454                          miocnak(q, mp, 0, error);
 555  455                          return;
 556  456                  }
 557  457                  tp->t_new_sgttyb = *((struct sgttyb *)mp->b_cont->b_rptr);
 558  458                  goto dogets;
 559  459  
 560  460          case TIOCSETC:
 561  461                  error = miocpullup(mp, sizeof (struct tchars));
 562  462                  if (error != 0) {
 563  463                          miocnak(q, mp, 0, error);
 564  464                          return;
 565  465                  }
 566  466                  tp->t_new_tchars = *((struct tchars *)mp->b_cont->b_rptr);
 567  467                  goto dogets;
 568  468  
 569  469          case TIOCSLTC:
 570  470                  error = miocpullup(mp, sizeof (struct ltchars));
 571  471                  if (error != 0) {
 572  472                          miocnak(q, mp, 0, error);
 573  473                          return;
 574  474                  }
 575  475                  tp->t_new_ltchars = *((struct ltchars *)mp->b_cont->b_rptr);
 576  476                  goto dogets;
 577  477  
 578  478          case TIOCLBIS:
 579  479          case TIOCLBIC:
 580  480          case TIOCLSET:
 581  481                  error = miocpullup(mp, sizeof (int));
 582  482                  if (error != 0) {
 583  483                          miocnak(q, mp, 0, error);
 584  484                          return;
 585  485                  }
 586  486                  tp->t_new_lflags = *(int *)mp->b_cont->b_rptr;
 587  487                  goto dogets;
 588  488  
 589  489          /*
 590  490           * "set"-style call that sets a particular bit in a "termios"
 591  491           * structure.  We then have to get the current state, so we
 592  492           * turn this guy into a TCGETS and pass it down.  When the
 593  493           * ACK comes back, we modify the state we got back and shove it
 594  494           * back down as the appropriate type of TCSETS.
 595  495           */
 596  496          case TIOCHPCL:
 597  497          dogets:
 598  498                  tp->t_ioccmd = iocp->ioc_cmd;
 599  499                  tp->t_iocid = iocp->ioc_id;
 600  500                  tp->t_state |= TS_IOCWAIT;
 601  501                  iocp->ioc_cmd = TCGETS;
 602  502                  iocp->ioc_count = 0;    /* no data returned unless we say so */
 603  503                  break;
 604  504  
 605  505          /*
 606  506           * "set"-style call that sets DTR.  Pretend that it was a TIOCMBIS
 607  507           * with TIOCM_DTR set.
 608  508           */
 609  509          case TIOCSDTR: {
 610  510                  mblk_t *datap;
 611  511  
 612  512                  if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL)
 613  513                          goto allocfailure;
 614  514                  *(int *)datap->b_wptr = TIOCM_DTR;
 615  515                  datap->b_wptr += sizeof (int);
 616  516                  iocp->ioc_cmd = TIOCMBIS;       /* turn it into a TIOCMBIS */
 617  517                  if (mp->b_cont != NULL)
 618  518                          freemsg(mp->b_cont);
 619  519                  mp->b_cont = datap;     /* attach the data */
 620  520                  iocp->ioc_count = sizeof (int); /* in case driver checks */
 621  521                  break;
 622  522          }
 623  523  
 624  524          /*
 625  525           * "set"-style call that clears DTR.  Pretend that it was a TIOCMBIC
 626  526           * with TIOCM_DTR set.
 627  527           */
 628  528          case TIOCCDTR: {
 629  529                  mblk_t *datap;
 630  530  
 631  531                  if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL)
 632  532                          goto allocfailure;
 633  533                  *(int *)datap->b_wptr = TIOCM_DTR;
 634  534                  datap->b_wptr += sizeof (int);
 635  535                  iocp->ioc_cmd = TIOCMBIC;       /* turn it into a TIOCMBIC */
 636  536                  if (mp->b_cont != NULL)
 637  537                          freemsg(mp->b_cont);
 638  538                  mp->b_cont = datap;     /* attach the data */
 639  539                  iocp->ioc_count = sizeof (int); /* in case driver checks */
 640  540                  break;
 641  541          }
 642  542  
 643  543          /*
 644  544           * Translate into the S5 form of TCFLSH.
 645  545           */
 646  546          case TIOCFLUSH: {
 647  547                  int flags;
 648  548  
 649  549                  error = miocpullup(mp, sizeof (int));
 650  550                  if (error != 0) {
 651  551                          miocnak(q, mp, 0, error);
 652  552                          return;
 653  553                  }
 654  554                  flags = *(int *)mp->b_cont->b_rptr;
 655  555  
 656  556                  switch (flags&(FREAD|FWRITE)) {
 657  557  
 658  558                  case 0:
 659  559                  case FREAD|FWRITE:
 660  560                          flags = 2;      /* flush 'em both */
 661  561                          break;
 662  562  
 663  563                  case FREAD:
 664  564                          flags = 0;      /* flush read */
 665  565                          break;
 666  566  
 667  567                  case FWRITE:
 668  568                          flags = 1;      /* flush write */
 669  569                          break;
 670  570                  }
 671  571                  iocp->ioc_cmd = TCFLSH; /* turn it into a TCFLSH */
 672  572                  *(int *)mp->b_cont->b_rptr = flags;     /* fiddle the arg */
 673  573                  break;
 674  574          }
 675  575  
 676  576          /*
 677  577           * Turn into a TCXONC.
 678  578           */
 679  579          case TIOCSTOP: {
 680  580                  mblk_t *datap;
 681  581  
 682  582                  if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL)
 683  583                          goto allocfailure;
 684  584                  *(int *)datap->b_wptr = 0;      /* stop */
 685  585                  datap->b_wptr += sizeof (int);
 686  586                  iocp->ioc_cmd = TCXONC; /* turn it into a XONC */
 687  587                  iocp->ioc_count = sizeof (int);
 688  588                  if (mp->b_cont != NULL)
 689  589                          freemsg(mp->b_cont);
 690  590                  mp->b_cont = datap;     /* attach the data */
 691  591                  break;
 692  592          }
 693  593  
 694  594          case TIOCSTART: {
 695  595                  mblk_t *datap;
 696  596  
 697  597                  if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL)
 698  598                          goto allocfailure;
 699  599                  *(int *)datap->b_wptr = 1;      /* start */
 700  600                  datap->b_wptr += sizeof (int);
 701  601                  iocp->ioc_cmd = TCXONC; /* turn it into a XONC */
 702  602                  iocp->ioc_count = sizeof (int);
 703  603                  if (mp->b_cont != NULL)
 704  604                          freemsg(mp->b_cont);
 705  605                  mp->b_cont = datap;     /* attach the data */
 706  606                  break;
 707  607          }
 708  608          case TIOCSETD:
 709  609          case TIOCGETD:
 710  610          case DIOCSETP:
 711  611          case DIOCGETP:
 712  612          case LDOPEN:
 713  613          case LDCLOSE:
 714  614          case LDCHG:
 715  615          case LDSETT:
 716  616          case LDGETT:
 717  617                  /*
 718  618                   * All of these ioctls are just ACK'd, except for
 719  619                   * TIOCSETD, which must be for line discipline zero.
 720  620                   */
 721  621                  mp->b_datap->db_type = M_IOCACK;
 722  622                  if (iocp->ioc_cmd == TIOCSETD) {
 723  623                          iocp->ioc_error = miocpullup(mp, sizeof (uchar_t));
 724  624                          if (iocp->ioc_error == 0 && (*mp->b_cont->b_rptr != 0))
 725  625                                  mp->b_datap->db_type = M_IOCNAK;
 726  626                  }
 727  627  
 728  628                  iocp->ioc_error = 0;
 729  629                  iocp->ioc_count = 0;
 730  630                  iocp->ioc_rval = 0;
 731  631                  qreply(q, mp);
 732  632                  return;
 733  633          case IOCTYPE:
 734  634                  mp->b_datap->db_type = M_IOCACK;
 735  635                  iocp->ioc_error = 0;
 736  636                  iocp->ioc_count = 0;
 737  637                  iocp->ioc_rval = TIOC;
 738  638                  qreply(q, mp);
 739  639                  return;
 740  640          case TIOCEXCL:
 741  641                  /* check for binary value of XCLUDE flag ???? */
 742  642                  tp->t_new_lflags |= XCLUDE;
 743  643                  mp->b_datap->db_type = M_IOCACK;
 744  644                  iocp->ioc_error = 0;
 745  645                  iocp->ioc_count = 0;
 746  646                  iocp->ioc_rval = 0;
 747  647                  qreply(q, mp);
 748  648                  return;
 749  649          case TIOCNXCL:
 750  650                  tp->t_new_lflags &= ~XCLUDE;
 751  651                  mp->b_datap->db_type = M_IOCACK;
 752  652                  iocp->ioc_error = 0;
 753  653                  iocp->ioc_count = 0;
 754  654                  iocp->ioc_rval = 0;
 755  655                  qreply(q, mp);
 756  656                  return;
 757  657          }
 758  658  
 759  659          /*
 760  660           * We don't reply to most calls, we just pass them down,
 761  661           * possibly after modifying the arguments.
 762  662           */
 763  663          putnext(q, mp);
 764  664          return;
 765  665  
 766  666  allocfailure:
 767  667          /*
 768  668           * We needed to allocate something to handle this "ioctl", but
 769  669           * couldn't; save this "ioctl" and arrange to get called back when
 770  670           * it's more likely that we can get what we need.
 771  671           * If there's already one being saved, throw it out, since it
 772  672           * must have timed out.
 773  673           */
 774  674          if (tp->t_iocpending != NULL)
 775  675                  freemsg(tp->t_iocpending);
 776  676          tp->t_iocpending = mp;  /* hold this ioctl */
 777  677          if (tp->t_bufcallid != 0)
 778  678                  qunbufcall(q, tp->t_bufcallid);
 779  679  
 780  680          tp->t_bufcallid = qbufcall(q, sizeof (struct iocblk), BPRI_HI,
 781  681              ttcompat_reioctl, q);
 782  682  }
 783  683  
 784  684  /*
 785  685   * Called when an M_IOCACK message is seen on the read queue; if this
 786  686   * is the response we were waiting for, we either:
 787  687   *    modify the data going up (if the "ioctl" read data); since in all
 788  688   *    cases, the old-style returned information is smaller than or the same
 789  689   *    size as the new-style returned information, we just overwrite the old
 790  690   *    stuff with the new stuff (beware of changing structure sizes, in case
 791  691   *    you invalidate this)
 792  692   * or
 793  693   *    take this data, modify it appropriately, and send it back down (if
 794  694   *    the "ioctl" wrote data).
 795  695   * In either case, we cancel the "wait"; the final response to a "write"
 796  696   * ioctl goes back up to the user.
 797  697   * If this wasn't the response we were waiting for, just pass it up.
 798  698   */
 799  699  static void
 800  700  ttcompat_ioctl_ack(queue_t *q,  mblk_t *mp)
 801  701  {
 802  702          ttcompat_state_t *tp;
 803  703          struct iocblk *iocp;
 804  704          mblk_t *datap;
 805  705  
 806  706          tp = (ttcompat_state_t *)q->q_ptr;
 807  707          iocp = (struct iocblk *)mp->b_rptr;
 808  708  
 809  709          if (!(tp->t_state&TS_IOCWAIT) || iocp->ioc_id != tp->t_iocid) {
 810  710                  /*
 811  711                   * This isn't the reply we're looking for.  Move along.
 812  712                   */
 813  713                  putnext(q, mp);
 814  714                  return;
 815  715          }
 816  716  
 817  717          datap = mp->b_cont;     /* mblk containing data going up */
 818  718  
 819  719          switch (tp->t_ioccmd) {
 820  720  
 821  721          case TIOCGETP: {
 822  722                  struct sgttyb *cb;
 823  723  
 824  724                  to_compat((struct termios *)datap->b_rptr, &tp->t_curstate);
 825  725                  datap->b_rptr = datap->b_wptr = datap->b_datap->db_base;
 826  726                          /* recycle the reply's buffer */
 827  727                  cb = (struct sgttyb *)datap->b_wptr;
 828  728                  /*
 829  729                   * This is used for TIOCGETP handling of sg_ispeed and
 830  730                   * sg_ospeed.  If the current speed is over 38400 (the
 831  731                   * sgttyb limit), then we report 38400.  Note that
 832  732                   * when "compatibility with old releases" is enabled
 833  733                   * (sgttyb_handling == 0), then t_[io]speed will have
 834  734                   * garbled nonsense, as in prior releases.  (See
 835  735                   * to_compat() below).
 836  736                   */
 837  737                  cb->sg_ispeed = tp->t_curstate.t_ispeed > B38400 ? B38400 :
 838  738                      tp->t_curstate.t_ispeed;
 839  739                  cb->sg_ospeed = tp->t_curstate.t_ospeed > B38400 ? B38400 :
 840  740                      tp->t_curstate.t_ospeed;
 841  741                  cb->sg_erase = tp->t_curstate.t_erase;
 842  742                  cb->sg_kill = tp->t_curstate.t_kill;
 843  743                  cb->sg_flags = tp->t_curstate.t_flags;
 844  744                  datap->b_wptr += sizeof (struct sgttyb);
 845  745                  iocp->ioc_count = sizeof (struct sgttyb);
 846  746  
 847  747                  /* you are lucky - stream head knows how to copy you out */
 848  748  
 849  749                  tp->t_state &= ~TS_IOCWAIT;     /* we got what we wanted */
 850  750                  iocp->ioc_rval = 0;
 851  751                  iocp->ioc_cmd =  tp->t_ioccmd;
 852  752                  putnext(q, mp);
 853  753                  return;
 854  754          }
 855  755  
 856  756          case TIOCGETC:
 857  757                  to_compat((struct termios *)datap->b_rptr, &tp->t_curstate);
 858  758                  datap->b_rptr = datap->b_wptr = datap->b_datap->db_base;
 859  759                          /* recycle the reply's buffer */
 860  760                  bcopy(&tp->t_curstate.t_intrc, datap->b_wptr,
 861  761                      sizeof (struct tchars));
 862  762                  datap->b_wptr += sizeof (struct tchars);
 863  763                  break;
 864  764  
 865  765          case TIOCGLTC:
 866  766                  to_compat((struct termios *)datap->b_rptr, &tp->t_curstate);
 867  767                  datap->b_rptr = datap->b_wptr = datap->b_datap->db_base;
 868  768                          /* recycle the reply's buffer */
 869  769                  bcopy(&tp->t_curstate.t_suspc, datap->b_wptr,
 870  770                      sizeof (struct ltchars));
 871  771                  datap->b_wptr += sizeof (struct ltchars);
 872  772                  break;
 873  773  
 874  774          case TIOCLGET:
 875  775                  to_compat((struct termios *)datap->b_rptr, &tp->t_curstate);
 876  776                  datap->b_rptr = datap->b_wptr = datap->b_datap->db_base;
 877  777                          /* recycle the reply's buffer */
 878  778                  *(int *)datap->b_wptr =
 879  779                      ((unsigned)tp->t_curstate.t_flags) >> 16;
 880  780                  datap->b_wptr += sizeof (int);
 881  781                  break;
 882  782  
 883  783          case TIOCSETP:
 884  784          case TIOCSETN:
 885  785                  /*
 886  786                   * Get the current state from the GETS data, and
 887  787                   * update it.
 888  788                   */
 889  789                  to_compat((struct termios *)datap->b_rptr, &tp->t_curstate);
 890  790                  tp->t_curstate.t_erase = tp->t_new_sgttyb.sg_erase;
 891  791                  tp->t_curstate.t_kill = tp->t_new_sgttyb.sg_kill;
 892  792                  /*
 893  793                   * For new-style handling, we ignore requests to set
 894  794                   * B38400 when the current speed is over B38400.  This
 895  795                   * means that we change the speed as requested if:
 896  796                   *      old style (sgttyb_handling == 0) is requested
 897  797                   *      the requested new speed isn't B38400
 898  798                   *      the current speed is at or below B38400
 899  799                   * Note that when old style is requested, both speeds
 900  800                   * in t_curstate are set to <= B38400 by to_compat, so
 901  801                   * the first test isn't needed here.
 902  802                   * Also note that we silently allow the user to set
 903  803                   * speeds above B38400 through this interface,
 904  804                   * regardless of the style setting.  This allows
 905  805                   * greater compatibility with current BSD releases.
 906  806                   */
 907  807                  if (tp->t_new_sgttyb.sg_ispeed != B38400 ||
 908  808                      tp->t_curstate.t_ispeed <= B38400)
 909  809                          tp->t_curstate.t_ispeed = tp->t_new_sgttyb.sg_ispeed;
 910  810                  if (tp->t_new_sgttyb.sg_ospeed != B38400 ||
 911  811                      tp->t_curstate.t_ospeed <= B38400)
 912  812                          tp->t_curstate.t_ospeed = tp->t_new_sgttyb.sg_ospeed;
 913  813                  tp->t_curstate.t_flags =
 914  814                      (tp->t_curstate.t_flags & 0xffff0000) |
 915  815                      (tp->t_new_sgttyb.sg_flags & 0xffff);
 916  816  
 917  817                  /*
 918  818                   * Replace the data that came up with the updated data.
 919  819                   */
 920  820                  from_compat(&tp->t_curstate, (struct termios *)datap->b_rptr);
 921  821  
 922  822                  /*
 923  823                   * Send it back down as a TCSETS or TCSETSF.
 924  824                   */
 925  825                  iocp->ioc_cmd = (tp->t_ioccmd == TIOCSETP) ? TCSETSF : TCSETS;
 926  826                  goto senddown;
 927  827  
 928  828          case TIOCSETC:
 929  829                  /*
 930  830                   * Get the current state from the GETS data, and
 931  831                   * update it.
 932  832                   */
 933  833                  to_compat((struct termios *)datap->b_rptr, &tp->t_curstate);
 934  834                  bcopy(&tp->t_new_tchars,
 935  835                      &tp->t_curstate.t_intrc, sizeof (struct tchars));
 936  836  
 937  837                  /*
 938  838                   * Replace the data that came up with the updated data.
 939  839                   */
 940  840                  from_compat(&tp->t_curstate, (struct termios *)datap->b_rptr);
 941  841  
 942  842                  /*
 943  843                   * Send it back down as a TCSETS.
 944  844                   */
 945  845                  iocp->ioc_cmd = TCSETS;
 946  846                  goto senddown;
 947  847  
 948  848          case TIOCSLTC:
 949  849                  /*
 950  850                   * Get the current state from the GETS data, and
 951  851                   * update it.
 952  852                   */
 953  853                  to_compat((struct termios *)datap->b_rptr, &tp->t_curstate);
 954  854                  bcopy(&tp->t_new_ltchars,
 955  855                      &tp->t_curstate.t_suspc, sizeof (struct ltchars));
 956  856  
 957  857                  /*
 958  858                   * Replace the data that came up with the updated data.
 959  859                   */
 960  860                  from_compat(&tp->t_curstate, (struct termios *)datap->b_rptr);
 961  861  
 962  862                  /*
 963  863                   * Send it back down as a TCSETS.
 964  864                   */
 965  865                  iocp->ioc_cmd = TCSETS;
 966  866                  goto senddown;
 967  867  
 968  868          case TIOCLBIS:
 969  869                  /*
 970  870                   * Get the current state from the GETS data, and
 971  871                   * update it.
 972  872                   */
 973  873                  to_compat((struct termios *)datap->b_rptr, &tp->t_curstate);
 974  874                  tp->t_curstate.t_flags |= (tp->t_new_lflags << 16);
 975  875  
 976  876                  /*
 977  877                   * Replace the data that came up with the updated data.
 978  878                   */
 979  879                  from_compat(&tp->t_curstate, (struct termios *)datap->b_rptr);
 980  880  
 981  881                  /*
 982  882                   * Send it back down as a TCSETS.
 983  883                   */
 984  884                  iocp->ioc_cmd = TCSETS;
 985  885                  goto senddown;
 986  886  
 987  887          case TIOCLBIC:
 988  888                  /*
 989  889                   * Get the current state from the GETS data, and
 990  890                   * update it.
 991  891                   */
 992  892                  to_compat((struct termios *)datap->b_rptr, &tp->t_curstate);
 993  893                  tp->t_curstate.t_flags &= ~(tp->t_new_lflags << 16);
 994  894  
 995  895                  /*
 996  896                   * Replace the data that came up with the updated data.
 997  897                   */
 998  898                  from_compat(&tp->t_curstate, (struct termios *)datap->b_rptr);
 999  899  
1000  900                  /*
1001  901                   * Send it back down as a TCSETS.
1002  902                   */
1003  903                  iocp->ioc_cmd = TCSETS;
1004  904                  goto senddown;
1005  905  
1006  906          case TIOCLSET:
1007  907                  /*
1008  908                   * Get the current state from the GETS data, and
1009  909                   * update it.
1010  910                   */
1011  911                  to_compat((struct termios *)datap->b_rptr, &tp->t_curstate);
1012  912                  tp->t_curstate.t_flags &= 0xffff;
1013  913                  tp->t_curstate.t_flags |= (tp->t_new_lflags << 16);
1014  914  
1015  915                  /*
1016  916                   * Replace the data that came up with the updated data.
1017  917                   */
1018  918                  from_compat(&tp->t_curstate, (struct termios *)datap->b_rptr);
1019  919  
1020  920                  /*
1021  921                   * Send it back down as a TCSETS.
1022  922                   */
1023  923                  iocp->ioc_cmd = TCSETS;
1024  924                  goto senddown;
1025  925  
1026  926          case TIOCHPCL:
1027  927                  /*
1028  928                   * Replace the data that came up with the updated data.
1029  929                   */
1030  930                  ((struct termios *)datap->b_rptr)->c_cflag |= HUPCL;
1031  931  
1032  932                  /*
1033  933                   * Send it back down as a TCSETS.
1034  934                   */
1035  935                  iocp->ioc_cmd = TCSETS;
1036  936                  goto senddown;
1037  937  
1038  938          case TCSETSF:
1039  939                  /*
1040  940                   * We're acknowledging the terminal reset ioctl that we sent
1041  941                   * when the module was opened.
1042  942                   */
1043  943                  tp->t_state &= ~(TS_IOCWAIT | TS_TIOCNAK);
1044  944                  freemsg(mp);
1045  945                  return;
1046  946  
1047  947          default:
1048  948                  cmn_err(CE_WARN, "ttcompat: Unexpected ioctl acknowledgment\n");
1049  949          }
1050  950  
1051  951          /*
1052  952           * All the calls that return something return 0.
1053  953           */
1054  954          tp->t_state &= ~TS_IOCWAIT;     /* we got what we wanted */
1055  955          iocp->ioc_rval = 0;
1056  956  
1057  957          /* copy out the data - ioctl transparency */
1058  958          iocp->ioc_cmd =  tp->t_ioccmd;
1059  959          ttcopyout(q, mp);
1060  960          return;
1061  961  
1062  962  senddown:
1063  963          /*
1064  964           * Send a "get state" reply back down, with suitably-modified
1065  965           * state, as a "set state" "ioctl".
1066  966           */
1067  967          tp->t_state &= ~TS_IOCWAIT;
1068  968          mp->b_datap->db_type = M_IOCTL;
1069  969          mp->b_wptr = mp->b_rptr + sizeof (struct iocblk);
1070  970          putnext(WR(q), mp);
1071  971  }
1072  972  /* Called from ttcompatrput M_IOCACK processing. */
1073  973  /* Copies out the data using M_COPYOUT messages */
1074  974  
1075  975  static void
1076  976  ttcopyout(queue_t *q, mblk_t *mp)
1077  977  {
1078  978          struct copyreq *cqp;
1079  979          ttcompat_state_t *tp;
1080  980  
1081  981          tp = (ttcompat_state_t *)q->q_ptr;
1082  982  
1083  983          mp->b_datap->db_type = M_COPYOUT;
1084  984          cqp = (struct copyreq *)mp->b_rptr;
1085  985          cqp->cq_addr = (caddr_t)tp->t_arg; /* retrieve the 3rd argument */
1086  986          tp->t_arg = 0; /* clear it since we don't need it anymore */
1087  987          switch (tp->t_ioccmd) {
1088  988                  case TIOCGLTC:
1089  989                          cqp->cq_size = sizeof (struct ltchars);
1090  990                          break;
1091  991                  case TIOCGETC:
1092  992                          cqp->cq_size = sizeof (struct tchars);
1093  993                          break;
1094  994                  case TIOCLGET:
1095  995                          cqp->cq_size = sizeof (int);
1096  996                          break;
1097  997                  default:
1098  998                          cmn_err(CE_WARN,
1099  999                              "ttcompat: Unknown ioctl to copyout\n");
1100 1000                          break;
1101 1001                  }
1102 1002          cqp->cq_flag = 0;
1103 1003          cqp->cq_private = NULL;
1104 1004          tp->t_state |= TS_W_OUT;
1105 1005          putnext(q, mp);
1106 1006  }
1107 1007  
1108 1008  
1109 1009  /*
1110 1010   * Called when an M_IOCNAK message is seen on the read queue; if this is
1111 1011   * the response we were waiting for, cancel the wait.  Pass the reply up;
1112 1012   * if we were waiting for this response, we can't complete the "ioctl" and
1113 1013   * the NAK will tell that to the guy above us.
1114 1014   * If this wasn't the response we were waiting for, just pass it up.
1115 1015   */
1116 1016  static void
1117 1017  ttcompat_ioctl_nak(queue_t *q, mblk_t *mp)
1118 1018  {
1119 1019          ttcompat_state_t *tp;
1120 1020          struct iocblk *iocp;
1121 1021  
1122 1022          iocp = (struct iocblk *)mp->b_rptr;
1123 1023          tp = (ttcompat_state_t *)q->q_ptr;
1124 1024  
1125 1025          if (tp->t_state&TS_IOCWAIT && iocp->ioc_id == tp->t_iocid) {
1126 1026                  tp->t_state &= ~TS_IOCWAIT; /* this call isn't going through */
1127 1027                  tp->t_arg = 0;  /* we may have stashed the 3rd argument */
1128 1028          }
1129 1029          putnext(q, mp);
1130 1030  }
1131 1031  
1132 1032  #define FROM_COMPAT_CHAR(to, from) { if ((to = from) == 0377) to = 0; }
1133 1033  
1134 1034  static void
1135 1035  from_compat(compat_state_t *csp, struct termios *termiosp)
1136 1036  {
1137 1037          termiosp->c_iflag = 0;
1138 1038          termiosp->c_oflag &= (ONLRET|ONOCR);
1139 1039  
1140 1040          termiosp->c_cflag = (termiosp->c_cflag &
1141 1041              (CRTSCTS|CRTSXOFF|PAREXT|LOBLK|HUPCL)) | CREAD;
1142 1042  
1143 1043          if (csp->t_ospeed > CBAUD) {
1144 1044                  termiosp->c_cflag |= ((csp->t_ospeed - CBAUD - 1) & CBAUD) |
1145 1045                      CBAUDEXT;
1146 1046          } else {
1147 1047                  termiosp->c_cflag |= csp->t_ospeed & CBAUD;
1148 1048          }
1149 1049  
1150 1050          if (csp->t_ospeed != csp->t_ispeed) {
1151 1051                  if (csp->t_ispeed > (CIBAUD >> IBSHIFT)) {
1152 1052                          termiosp->c_cflag |= CIBAUDEXT |
1153 1053                              (((csp->t_ispeed - (CIBAUD >> IBSHIFT) - 1) <<
1154 1054                              IBSHIFT) & CIBAUD);
1155 1055                  } else {
1156 1056                          termiosp->c_cflag |= (csp->t_ispeed << IBSHIFT) &
1157 1057                              CIBAUD;
1158 1058                  }
1159 1059                  /* hang up if ispeed=0 */
1160 1060                  if (csp->t_ispeed == 0)
1161 1061                          termiosp->c_cflag &= ~CBAUD & ~CBAUDEXT;
1162 1062          }
1163 1063          if (csp->t_ispeed == B110 || csp->t_xflags & STOPB)
1164 1064                  termiosp->c_cflag |= CSTOPB;
1165 1065          termiosp->c_lflag = ECHOK;
1166 1066          FROM_COMPAT_CHAR(termiosp->c_cc[VERASE], csp->t_erase);
1167 1067          FROM_COMPAT_CHAR(termiosp->c_cc[VKILL], csp->t_kill);
1168 1068          FROM_COMPAT_CHAR(termiosp->c_cc[VINTR], csp->t_intrc);
1169 1069          FROM_COMPAT_CHAR(termiosp->c_cc[VQUIT], csp->t_quitc);
1170 1070          FROM_COMPAT_CHAR(termiosp->c_cc[VSTART], csp->t_startc);
1171 1071          FROM_COMPAT_CHAR(termiosp->c_cc[VSTOP], csp->t_stopc);
1172 1072          termiosp->c_cc[VEOL2] = 0;
1173 1073          FROM_COMPAT_CHAR(termiosp->c_cc[VSUSP], csp->t_suspc);
1174 1074          /* is this useful? */
1175 1075          FROM_COMPAT_CHAR(termiosp->c_cc[VDSUSP], csp->t_dsuspc);
1176 1076          FROM_COMPAT_CHAR(termiosp->c_cc[VREPRINT], csp->t_rprntc);
1177 1077          FROM_COMPAT_CHAR(termiosp->c_cc[VDISCARD], csp->t_flushc);
1178 1078          FROM_COMPAT_CHAR(termiosp->c_cc[VWERASE], csp->t_werasc);
1179 1079          FROM_COMPAT_CHAR(termiosp->c_cc[VLNEXT], csp->t_lnextc);
1180 1080          termiosp->c_cc[VSTATUS] = 0;
1181 1081          if (csp->t_flags & O_TANDEM)
1182 1082                  termiosp->c_iflag |= IXOFF;
1183 1083          if (csp->t_flags & O_LCASE) {
1184 1084                  termiosp->c_iflag |= IUCLC;
1185 1085                  termiosp->c_oflag |= OLCUC;
1186 1086                  termiosp->c_lflag |= XCASE;
1187 1087          }
1188 1088          if (csp->t_flags & O_ECHO)
1189 1089                  termiosp->c_lflag |= ECHO;
1190 1090          if (csp->t_flags & O_CRMOD) {
1191 1091                  termiosp->c_iflag |= ICRNL;
1192 1092                  termiosp->c_oflag |= ONLCR;
1193 1093                  switch (csp->t_flags & O_CRDELAY) {
1194 1094  
1195 1095                  case O_CR1:
1196 1096                          termiosp->c_oflag |= CR2;
1197 1097                          break;
1198 1098  
1199 1099                  case O_CR2:
1200 1100                          termiosp->c_oflag |= CR3;
1201 1101                          break;
1202 1102                  }
1203 1103          } else {
1204 1104                  if ((csp->t_flags & O_NLDELAY) == O_NL1)
1205 1105                          termiosp->c_oflag |= ONLRET|CR1;        /* tty37 */
1206 1106          }
1207 1107          if ((csp->t_flags & O_NLDELAY) == O_NL2)
1208 1108                  termiosp->c_oflag |= NL1;
1209 1109          /*
1210 1110           * When going into RAW mode, the special characters controlled by the
1211 1111           * POSIX IEXTEN bit no longer apply; when leaving, they do.
1212 1112           */
1213 1113          if (csp->t_flags & O_RAW) {
1214 1114                  termiosp->c_cflag |= CS8;
1215 1115                  termiosp->c_iflag &= ~(ICRNL|IUCLC);
1216 1116                  termiosp->c_lflag &= ~(XCASE|IEXTEN);
1217 1117          } else {
1218 1118                  termiosp->c_iflag |= IMAXBEL|BRKINT|IGNPAR;
1219 1119                  if (termiosp->c_cc[VSTOP] != 0 && termiosp->c_cc[VSTART] != 0)
1220 1120                          termiosp->c_iflag |= IXON;
1221 1121                  if (csp->t_flags & O_LITOUT)
1222 1122                          termiosp->c_cflag |= CS8;
1223 1123                  else {
1224 1124                          if (csp->t_flags & O_PASS8)
1225 1125                                  termiosp->c_cflag |= CS8;
1226 1126                                  /* XXX - what about 8 bits plus parity? */
1227 1127                          else {
1228 1128                                  switch (csp->t_flags & (O_EVENP|O_ODDP)) {
1229 1129  
1230 1130                                  case 0:
1231 1131                                          termiosp->c_iflag |= ISTRIP;
1232 1132                                          termiosp->c_cflag |= CS8;
1233 1133                                          break;
1234 1134  
1235 1135                                  case O_EVENP:
1236 1136                                          termiosp->c_iflag |= INPCK|ISTRIP;
1237 1137                                          termiosp->c_cflag |= CS7|PARENB;
1238 1138                                          break;
1239 1139  
1240 1140                                  case O_ODDP:
1241 1141                                          termiosp->c_iflag |= INPCK|ISTRIP;
1242 1142                                          termiosp->c_cflag |= CS7|PARENB|PARODD;
1243 1143                                          break;
1244 1144  
1245 1145                                  case O_EVENP|O_ODDP:
1246 1146                                          termiosp->c_iflag |= ISTRIP;
1247 1147                                          termiosp->c_cflag |= CS7|PARENB;
1248 1148                                          break;
1249 1149                                  }
1250 1150                          }
1251 1151                          if (!(csp->t_xflags & NOPOST))
1252 1152                                  termiosp->c_oflag |= OPOST;
1253 1153                  }
1254 1154                  termiosp->c_lflag |= IEXTEN;
1255 1155                  if (!(csp->t_xflags & NOISIG))
1256 1156                          termiosp->c_lflag |= ISIG;
1257 1157                  if (!(csp->t_flags & O_CBREAK))
1258 1158                          termiosp->c_lflag |= ICANON;
1259 1159                  if (csp->t_flags & O_CTLECH)
1260 1160                          termiosp->c_lflag |= ECHOCTL;
1261 1161          }
1262 1162          switch (csp->t_flags & O_TBDELAY) {
1263 1163  
1264 1164          case O_TAB1:
1265 1165                  termiosp->c_oflag |= TAB1;
1266 1166                  break;
1267 1167  
1268 1168          case O_TAB2:
1269 1169                  termiosp->c_oflag |= TAB2;
1270 1170                  break;
1271 1171  
1272 1172          case O_XTABS:
1273 1173                  termiosp->c_oflag |= TAB3;
1274 1174                  break;
1275 1175          }
1276 1176          if (csp->t_flags & O_VTDELAY)
1277 1177                  termiosp->c_oflag |= FFDLY;
1278 1178          if (csp->t_flags & O_BSDELAY)
1279 1179                  termiosp->c_oflag |= BSDLY;
1280 1180          if (csp->t_flags & O_PRTERA)
1281 1181                  termiosp->c_lflag |= ECHOPRT;
1282 1182          if (csp->t_flags & O_CRTERA)
1283 1183                  termiosp->c_lflag |= ECHOE;
1284 1184          if (csp->t_flags & O_TOSTOP)
1285 1185                  termiosp->c_lflag |= TOSTOP;
1286 1186          if (csp->t_flags & O_FLUSHO)
1287 1187                  termiosp->c_lflag |= FLUSHO;
1288 1188          if (csp->t_flags & O_NOHANG)
1289 1189                  termiosp->c_cflag |= CLOCAL;
1290 1190          if (csp->t_flags & O_CRTKIL)
1291 1191                  termiosp->c_lflag |= ECHOKE;
1292 1192          if (csp->t_flags & O_PENDIN)
1293 1193                  termiosp->c_lflag |= PENDIN;
1294 1194          if (!(csp->t_flags & O_DECCTQ))
1295 1195                  termiosp->c_iflag |= IXANY;
1296 1196          if (csp->t_flags & O_NOFLSH)
1297 1197                  termiosp->c_lflag |= NOFLSH;
1298 1198          if (termiosp->c_lflag & ICANON) {
1299 1199                  FROM_COMPAT_CHAR(termiosp->c_cc[VEOF], csp->t_eofc);
1300 1200                  FROM_COMPAT_CHAR(termiosp->c_cc[VEOL], csp->t_brkc);
1301 1201          } else {
1302 1202                  termiosp->c_cc[VMIN] = 1;
1303 1203                  termiosp->c_cc[VTIME] = 0;
1304 1204          }
1305 1205  }
1306 1206  
1307 1207  #define TO_COMPAT_CHAR(to, from) { if ((to = from) == 0) to = (uchar_t)0377; }
1308 1208  
1309 1209  static void
1310 1210  to_compat(struct termios *termiosp, compat_state_t *csp)
1311 1211  {
1312 1212          csp->t_xflags &= (NOISIG|NOPOST);
1313 1213          csp->t_ospeed = termiosp->c_cflag & CBAUD;
1314 1214          csp->t_ispeed = (termiosp->c_cflag & CIBAUD) >> IBSHIFT;
1315 1215          if (sgttyb_handling > 0) {
1316 1216                  if (termiosp->c_cflag & CBAUDEXT)
1317 1217                          csp->t_ospeed += CBAUD + 1;
1318 1218                  if (termiosp->c_cflag & CIBAUDEXT)
1319 1219                          csp->t_ispeed += (CIBAUD >> IBSHIFT) + 1;
1320 1220          }
1321 1221          if (csp->t_ispeed == 0)
1322 1222                  csp->t_ispeed = csp->t_ospeed;
1323 1223          if ((termiosp->c_cflag & CSTOPB) && csp->t_ispeed != B110)
1324 1224                  csp->t_xflags |= STOPB;
1325 1225          TO_COMPAT_CHAR(csp->t_erase, termiosp->c_cc[VERASE]);
1326 1226          TO_COMPAT_CHAR(csp->t_kill, termiosp->c_cc[VKILL]);
1327 1227          TO_COMPAT_CHAR(csp->t_intrc, termiosp->c_cc[VINTR]);
1328 1228          TO_COMPAT_CHAR(csp->t_quitc, termiosp->c_cc[VQUIT]);
1329 1229          TO_COMPAT_CHAR(csp->t_startc, termiosp->c_cc[VSTART]);
1330 1230          TO_COMPAT_CHAR(csp->t_stopc, termiosp->c_cc[VSTOP]);
1331 1231          TO_COMPAT_CHAR(csp->t_suspc, termiosp->c_cc[VSUSP]);
1332 1232          TO_COMPAT_CHAR(csp->t_dsuspc, termiosp->c_cc[VDSUSP]);
1333 1233          TO_COMPAT_CHAR(csp->t_rprntc, termiosp->c_cc[VREPRINT]);
1334 1234          TO_COMPAT_CHAR(csp->t_flushc, termiosp->c_cc[VDISCARD]);
1335 1235          TO_COMPAT_CHAR(csp->t_werasc, termiosp->c_cc[VWERASE]);
1336 1236          TO_COMPAT_CHAR(csp->t_lnextc, termiosp->c_cc[VLNEXT]);
1337 1237          csp->t_flags &= (O_CTLECH|O_LITOUT|O_PASS8|O_ODDP|O_EVENP);
1338 1238          if (termiosp->c_iflag & IXOFF)
1339 1239                  csp->t_flags |= O_TANDEM;
1340 1240          if (!(termiosp->c_iflag &
1341 1241              (IMAXBEL|BRKINT|IGNPAR|PARMRK|INPCK|ISTRIP|
1342 1242              INLCR|IGNCR|ICRNL|IUCLC|IXON)) &&
1343 1243              !(termiosp->c_oflag & OPOST) &&
1344 1244              (termiosp->c_cflag & (CSIZE|PARENB)) == CS8 &&
1345 1245              !(termiosp->c_lflag & (ISIG|ICANON|XCASE|IEXTEN)))
1346 1246                  csp->t_flags |= O_RAW;
1347 1247          else {
1348 1248                  if (!(termiosp->c_iflag & IXON)) {
1349 1249                          csp->t_startc = (uchar_t)0377;
1350 1250                          csp->t_stopc = (uchar_t)0377;
1351 1251                  }
1352 1252                  if ((termiosp->c_cflag & (CSIZE|PARENB)) == CS8 &&
1353 1253                      !(termiosp->c_oflag & OPOST))
1354 1254                          csp->t_flags |= O_LITOUT;
1355 1255                  else {
1356 1256                          csp->t_flags &= ~O_LITOUT;
1357 1257                          if ((termiosp->c_cflag & (CSIZE|PARENB)) == CS8) {
1358 1258                                  if (!(termiosp->c_iflag & ISTRIP))
1359 1259                                          csp->t_flags |= O_PASS8;
1360 1260                          } else {
1361 1261                                  csp->t_flags &= ~(O_ODDP|O_EVENP|O_PASS8);
1362 1262                                  if (termiosp->c_cflag & PARODD)
1363 1263                                          csp->t_flags |= O_ODDP;
1364 1264                                  else if (termiosp->c_iflag & INPCK)
1365 1265                                          csp->t_flags |= O_EVENP;
1366 1266                                  else
1367 1267                                          csp->t_flags |= O_ODDP|O_EVENP;
1368 1268                          }
1369 1269                          if (!(termiosp->c_oflag & OPOST))
1370 1270                                  csp->t_xflags |= NOPOST;
1371 1271                          else
1372 1272                                  csp->t_xflags &= ~NOPOST;
1373 1273                  }
1374 1274                  if (!(termiosp->c_lflag & ISIG))
1375 1275                          csp->t_xflags |= NOISIG;
1376 1276                  else
1377 1277                          csp->t_xflags &= ~NOISIG;
1378 1278                  if (!(termiosp->c_lflag & ICANON))
1379 1279                          csp->t_flags |= O_CBREAK;
1380 1280                  if (termiosp->c_lflag & ECHOCTL)
1381 1281                          csp->t_flags |= O_CTLECH;
1382 1282                  else
1383 1283                          csp->t_flags &= ~O_CTLECH;
1384 1284          }
1385 1285          if (termiosp->c_oflag & OLCUC)
1386 1286                  csp->t_flags |= O_LCASE;
1387 1287          if (termiosp->c_lflag&ECHO)
1388 1288                  csp->t_flags |= O_ECHO;
1389 1289          if (termiosp->c_oflag & ONLCR) {
1390 1290                  csp->t_flags |= O_CRMOD;
1391 1291                  switch (termiosp->c_oflag & CRDLY) {
1392 1292  
1393 1293                  case CR2:
1394 1294                          csp->t_flags |= O_CR1;
1395 1295                          break;
1396 1296  
1397 1297                  case CR3:
1398 1298                          csp->t_flags |= O_CR2;
1399 1299                          break;
1400 1300                  }
1401 1301          } else {
1402 1302                  if ((termiosp->c_oflag & CR1) &&
1403 1303                      (termiosp->c_oflag & ONLRET))
1404 1304                          csp->t_flags |= O_NL1;  /* tty37 */
1405 1305          }
1406 1306          if ((termiosp->c_oflag & ONLRET) && (termiosp->c_oflag & NL1))
1407 1307                  csp->t_flags |= O_NL2;
1408 1308          switch (termiosp->c_oflag & TABDLY) {
1409 1309  
1410 1310          case TAB1:
1411 1311                  csp->t_flags |= O_TAB1;
1412 1312                  break;
1413 1313  
1414 1314          case TAB2:
1415 1315                  csp->t_flags |= O_TAB2;
1416 1316                  break;
1417 1317  
1418 1318          case XTABS:
1419 1319                  csp->t_flags |= O_XTABS;
1420 1320                  break;
1421 1321          }
1422 1322          if (termiosp->c_oflag & FFDLY)
1423 1323                  csp->t_flags |= O_VTDELAY;
1424 1324          if (termiosp->c_oflag & BSDLY)
1425 1325                  csp->t_flags |= O_BSDELAY;
1426 1326          if (termiosp->c_lflag & ECHOPRT)
1427 1327                  csp->t_flags |= O_PRTERA;
1428 1328          if (termiosp->c_lflag & ECHOE)
1429 1329                  csp->t_flags |= (O_CRTERA|O_CRTBS);
1430 1330          if (termiosp->c_lflag & TOSTOP)
1431 1331                  csp->t_flags |= O_TOSTOP;
1432 1332          if (termiosp->c_lflag & FLUSHO)
1433 1333                  csp->t_flags |= O_FLUSHO;
1434 1334          if (termiosp->c_cflag & CLOCAL)
1435 1335                  csp->t_flags |= O_NOHANG;
1436 1336          if (termiosp->c_lflag & ECHOKE)
1437 1337                  csp->t_flags |= O_CRTKIL;
1438 1338          if (termiosp->c_lflag & PENDIN)
1439 1339                  csp->t_flags |= O_PENDIN;
1440 1340          if (!(termiosp->c_iflag & IXANY))
1441 1341                  csp->t_flags |= O_DECCTQ;
1442 1342          if (termiosp->c_lflag & NOFLSH)
1443 1343                  csp->t_flags |= O_NOFLSH;
1444 1344          if (termiosp->c_lflag & ICANON) {
1445 1345                  TO_COMPAT_CHAR(csp->t_eofc, termiosp->c_cc[VEOF]);
1446 1346                  TO_COMPAT_CHAR(csp->t_brkc, termiosp->c_cc[VEOL]);
1447 1347          } else {
1448 1348                  termiosp->c_cc[VMIN] = 1;
1449 1349                  termiosp->c_cc[VTIME] = 0;
1450 1350          }
1451 1351  }
  
    | 
      ↓ open down ↓ | 
    1151 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX