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