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