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 /* FALLTHROUGH */ 423 default: 424 putnext(q, mp); 425 break; 426 } 427 } 428 429 430 /* 431 * ptemwput - Module write queue put procedure. 432 * 433 * This is called from the module or stream head upstream. 434 * 435 * XXX: This routine is quite lazy about handling allocation failures, 436 * basically just giving up and reporting failure. It really ought to 437 * set up bufcalls and only fail when it's absolutely necessary. 438 */ 439 static void 440 ptemwput(queue_t *q, mblk_t *mp) 441 { 442 struct ptem *ntp = (struct ptem *)q->q_ptr; 443 struct iocblk *iocp; /* outgoing ioctl structure */ 444 struct copyresp *resp; 445 unsigned char type = mp->b_datap->db_type; 446 447 if (type >= QPCTL) { 448 switch (type) { 449 450 case M_IOCDATA: 451 resp = (struct copyresp *)mp->b_rptr; 452 if (resp->cp_rval) { 453 /* 454 * Just free message on failure. 455 */ 456 freemsg(mp); 457 break; 458 } 459 460 /* 461 * Only need to copy data for the SET case. 462 */ 463 switch (resp->cp_cmd) { 464 465 case TIOCSWINSZ: 466 ptioc(q, mp, WRSIDE); 467 break; 468 469 case JWINSIZE: 470 case TIOCGWINSZ: 471 mioc2ack(mp, NULL, 0, 0); 472 qreply(q, mp); 473 break; 474 475 default: 476 freemsg(mp); 477 } 478 break; 479 480 case M_FLUSH: 481 if (*mp->b_rptr & FLUSHW) { 482 if ((ntp->state & IS_PTSTTY) && 483 (*mp->b_rptr & FLUSHBAND)) 484 flushband(q, *(mp->b_rptr + 1), 485 FLUSHDATA); 486 else 487 flushq(q, FLUSHDATA); 488 } 489 putnext(q, mp); 490 break; 491 492 case M_READ: 493 freemsg(mp); 494 break; 495 496 case M_STOP: 497 /* 498 * Set the output flow control state. 499 */ 500 ntp->state |= OFLOW_CTL; 501 putnext(q, mp); 502 break; 503 504 case M_START: 505 /* 506 * Relieve the output flow control state. 507 */ 508 ntp->state &= ~OFLOW_CTL; 509 putnext(q, mp); 510 qenable(q); 511 break; 512 default: 513 putnext(q, mp); 514 break; 515 } 516 return; 517 } 518 /* 519 * If our queue is nonempty or flow control persists 520 * downstream or module in stopped state, queue this message. 521 */ 522 if (q->q_first != NULL || !bcanputnext(q, mp->b_band)) { 523 /* 524 * Exception: ioctls, except for those defined to 525 * take effect after output has drained, should be 526 * processed immediately. 527 */ 528 switch (type) { 529 530 case M_IOCTL: 531 iocp = (struct iocblk *)mp->b_rptr; 532 switch (iocp->ioc_cmd) { 533 /* 534 * Queue these. 535 */ 536 case TCSETSW: 537 case TCSETSF: 538 case TCSETAW: 539 case TCSETAF: 540 case TCSBRK: 541 break; 542 543 /* 544 * Handle all others immediately. 545 */ 546 default: 547 (void) ptemwmsg(q, mp); 548 return; 549 } 550 break; 551 552 case M_DELAY: /* tty delays not supported */ 553 freemsg(mp); 554 return; 555 556 case M_DATA: 557 if ((mp->b_wptr - mp->b_rptr) < 0) { 558 /* 559 * Free all bad length messages. 560 */ 561 freemsg(mp); 562 return; 563 } else if ((mp->b_wptr - mp->b_rptr) == 0) { 564 if (!(ntp->state & IS_PTSTTY)) { 565 freemsg(mp); 566 return; 567 } 568 } 569 } 570 (void) putq(q, mp); 571 return; 572 } 573 /* 574 * fast path into ptemwmsg to dispose of mp. 575 */ 576 if (!ptemwmsg(q, mp)) 577 (void) putq(q, mp); 578 } 579 580 /* 581 * ptem write queue service procedure. 582 */ 583 static void 584 ptemwsrv(queue_t *q) 585 { 586 mblk_t *mp; 587 588 while ((mp = getq(q)) != NULL) { 589 if (!bcanputnext(q, mp->b_band) || !ptemwmsg(q, mp)) { 590 (void) putbq(q, mp); 591 break; 592 } 593 } 594 } 595 596 597 /* 598 * This routine is called from both ptemwput and ptemwsrv to do the 599 * actual work of dealing with mp. ptmewput will have already 600 * dealt with high priority messages. 601 * 602 * Return 1 if the message was processed completely and 0 if not. 603 */ 604 static int 605 ptemwmsg(queue_t *q, mblk_t *mp) 606 { 607 struct ptem *ntp = (struct ptem *)q->q_ptr; 608 struct iocblk *iocp; /* outgoing ioctl structure */ 609 struct termio *termiop; 610 struct termios *termiosp; 611 mblk_t *dack_ptr; /* disconnect message ACK block */ 612 mblk_t *pckt_msgp; /* message sent to the PCKT module */ 613 mblk_t *dp; /* ioctl reply data */ 614 tcflag_t cflags; 615 int error; 616 617 switch (mp->b_datap->db_type) { 618 619 case M_IOCTL: 620 /* 621 * Note: for each "set" type operation a copy 622 * of the M_IOCTL message is made and passed 623 * downstream. Eventually the PCKT module, if 624 * it has been pushed, should pick up this message. 625 * If the PCKT module has not been pushed the master 626 * side stream head will free it. 627 */ 628 iocp = (struct iocblk *)mp->b_rptr; 629 switch (iocp->ioc_cmd) { 630 631 case TCSETAF: 632 case TCSETSF: 633 /* 634 * Flush the read queue. 635 */ 636 if (putnextctl1(q, M_FLUSH, FLUSHR) == 0) { 637 miocnak(q, mp, 0, EAGAIN); 638 break; 639 } 640 /* FALLTHROUGH */ 641 642 case TCSETA: 643 case TCSETAW: 644 case TCSETS: 645 case TCSETSW: 646 647 switch (iocp->ioc_cmd) { 648 case TCSETAF: 649 case TCSETA: 650 case TCSETAW: 651 error = miocpullup(mp, sizeof (struct termio)); 652 if (error != 0) { 653 miocnak(q, mp, 0, error); 654 goto out; 655 } 656 cflags = ((struct termio *) 657 mp->b_cont->b_rptr)->c_cflag; 658 ntp->cflags = 659 (ntp->cflags & 0xffff0000 | cflags); 660 break; 661 662 case TCSETSF: 663 case TCSETS: 664 case TCSETSW: 665 error = miocpullup(mp, sizeof (struct termios)); 666 if (error != 0) { 667 miocnak(q, mp, 0, error); 668 goto out; 669 } 670 cflags = ((struct termios *) 671 mp->b_cont->b_rptr)->c_cflag; 672 ntp->cflags = cflags; 673 break; 674 } 675 676 if ((cflags & CBAUD) == B0) { 677 /* 678 * Hang-up: Send a zero length message. 679 */ 680 dack_ptr = ntp->dack_ptr; 681 682 if (dack_ptr) { 683 ntp->dack_ptr = NULL; 684 /* 685 * Send a zero length message 686 * downstream. 687 */ 688 putnext(q, dack_ptr); 689 } 690 } else { 691 /* 692 * Make a copy of this message and pass it on 693 * to the PCKT module. 694 */ 695 if ((pckt_msgp = copymsg(mp)) == NULL) { 696 miocnak(q, mp, 0, EAGAIN); 697 break; 698 } 699 putnext(q, pckt_msgp); 700 } 701 /* 702 * Send ACK upstream. 703 */ 704 mioc2ack(mp, NULL, 0, 0); 705 qreply(q, mp); 706 out: 707 break; 708 709 case TCGETA: 710 dp = allocb(sizeof (struct termio), BPRI_MED); 711 if (dp == NULL) { 712 miocnak(q, mp, 0, EAGAIN); 713 break; 714 } 715 termiop = (struct termio *)dp->b_rptr; 716 termiop->c_cflag = (ushort_t)ntp->cflags; 717 mioc2ack(mp, dp, sizeof (struct termio), 0); 718 qreply(q, mp); 719 break; 720 721 case TCGETS: 722 dp = allocb(sizeof (struct termios), BPRI_MED); 723 if (dp == NULL) { 724 miocnak(q, mp, 0, EAGAIN); 725 break; 726 } 727 termiosp = (struct termios *)dp->b_rptr; 728 termiosp->c_cflag = ntp->cflags; 729 mioc2ack(mp, dp, sizeof (struct termios), 0); 730 qreply(q, mp); 731 break; 732 733 case TCSBRK: 734 error = miocpullup(mp, sizeof (int)); 735 if (error != 0) { 736 miocnak(q, mp, 0, error); 737 break; 738 } 739 740 /* 741 * Need a copy of this message to pass it on to 742 * the PCKT module. 743 */ 744 if ((pckt_msgp = copymsg(mp)) == NULL) { 745 miocnak(q, mp, 0, EAGAIN); 746 break; 747 } 748 /* 749 * Send a copy of the M_IOCTL to the PCKT module. 750 */ 751 putnext(q, pckt_msgp); 752 753 /* 754 * TCSBRK meaningful if data part of message is 0 755 * cf. termio(7). 756 */ 757 if (!(*(int *)mp->b_cont->b_rptr)) 758 (void) putnextctl(q, M_BREAK); 759 /* 760 * ACK the ioctl. 761 */ 762 mioc2ack(mp, NULL, 0, 0); 763 qreply(q, mp); 764 break; 765 766 case JWINSIZE: 767 case TIOCGWINSZ: 768 case TIOCSWINSZ: 769 ptioc(q, mp, WRSIDE); 770 break; 771 772 case TIOCSTI: 773 /* 774 * Simulate typing of a character at the terminal. In 775 * all cases, we acknowledge the ioctl and pass a copy 776 * of it along for the PCKT module to encapsulate. If 777 * not in remote mode, we also process the ioctl 778 * itself, looping the character given as its argument 779 * back around to the read side. 780 */ 781 782 /* 783 * Need a copy of this message to pass on to the PCKT 784 * module. 785 */ 786 if ((pckt_msgp = copymsg(mp)) == NULL) { 787 miocnak(q, mp, 0, EAGAIN); 788 break; 789 } 790 if ((ntp->state & REMOTEMODE) == 0) { 791 mblk_t *bp; 792 793 error = miocpullup(mp, sizeof (char)); 794 if (error != 0) { 795 freemsg(pckt_msgp); 796 miocnak(q, mp, 0, error); 797 break; 798 } 799 800 /* 801 * The permission checking has already been 802 * done at the stream head, since it has to be 803 * done in the context of the process doing 804 * the call. 805 */ 806 if ((bp = allocb(1, BPRI_MED)) == NULL) { 807 freemsg(pckt_msgp); 808 miocnak(q, mp, 0, EAGAIN); 809 break; 810 } 811 /* 812 * XXX: Is EAGAIN really the right response to 813 * flow control blockage? 814 */ 815 if (!bcanputnext(RD(q), mp->b_band)) { 816 freemsg(bp); 817 freemsg(pckt_msgp); 818 miocnak(q, mp, 0, EAGAIN); 819 break; 820 } 821 *bp->b_wptr++ = *mp->b_cont->b_rptr; 822 qreply(q, bp); 823 } 824 825 putnext(q, pckt_msgp); 826 mioc2ack(mp, NULL, 0, 0); 827 qreply(q, mp); 828 break; 829 830 case PTSSTTY: 831 if (ntp->state & IS_PTSTTY) { 832 miocnak(q, mp, 0, EEXIST); 833 } else { 834 ntp->state |= IS_PTSTTY; 835 mioc2ack(mp, NULL, 0, 0); 836 qreply(q, mp); 837 } 838 break; 839 840 default: 841 /* 842 * End of the line. The slave driver doesn't see any 843 * ioctls that we don't explicitly pass along to it. 844 */ 845 miocnak(q, mp, 0, EINVAL); 846 break; 847 } 848 break; 849 850 case M_DELAY: /* tty delays not supported */ 851 freemsg(mp); 852 break; 853 854 case M_DATA: 855 if ((mp->b_wptr - mp->b_rptr) < 0) { 856 /* 857 * Free all bad length messages. 858 */ 859 freemsg(mp); 860 break; 861 } else if ((mp->b_wptr - mp->b_rptr) == 0) { 862 if (!(ntp->state & IS_PTSTTY)) { 863 freemsg(mp); 864 break; 865 } 866 } 867 if (ntp->state & OFLOW_CTL) 868 return (0); 869 /* FALLTHROUGH */ 870 871 default: 872 putnext(q, mp); 873 break; 874 875 } 876 877 return (1); 878 } 879 880 /* 881 * Message must be of type M_IOCTL or M_IOCDATA for this routine to be called. 882 */ 883 static void 884 ptioc(queue_t *q, mblk_t *mp, int qside) 885 { 886 struct ptem *tp; 887 struct iocblk *iocp; 888 struct winsize *wb; 889 struct jwinsize *jwb; 890 mblk_t *tmp; 891 mblk_t *pckt_msgp; /* message sent to the PCKT module */ 892 int error; 893 894 iocp = (struct iocblk *)mp->b_rptr; 895 tp = (struct ptem *)q->q_ptr; 896 897 switch (iocp->ioc_cmd) { 898 899 case JWINSIZE: 900 /* 901 * For compatibility: If all zeros, NAK the message for dumb 902 * terminals. 903 */ 904 if ((tp->wsz.ws_row == 0) && (tp->wsz.ws_col == 0) && 905 (tp->wsz.ws_xpixel == 0) && (tp->wsz.ws_ypixel == 0)) { 906 miocnak(q, mp, 0, EINVAL); 907 return; 908 } 909 910 tmp = allocb(sizeof (struct jwinsize), BPRI_MED); 911 if (tmp == NULL) { 912 miocnak(q, mp, 0, EAGAIN); 913 return; 914 } 915 916 if (iocp->ioc_count == TRANSPARENT) 917 mcopyout(mp, NULL, sizeof (struct jwinsize), NULL, tmp); 918 else 919 mioc2ack(mp, tmp, sizeof (struct jwinsize), 0); 920 921 jwb = (struct jwinsize *)mp->b_cont->b_rptr; 922 jwb->bytesx = tp->wsz.ws_col; 923 jwb->bytesy = tp->wsz.ws_row; 924 jwb->bitsx = tp->wsz.ws_xpixel; 925 jwb->bitsy = tp->wsz.ws_ypixel; 926 927 qreply(q, mp); 928 return; 929 930 case TIOCGWINSZ: 931 /* 932 * If all zeros NAK the message for dumb terminals. 933 */ 934 if ((tp->wsz.ws_row == 0) && (tp->wsz.ws_col == 0) && 935 (tp->wsz.ws_xpixel == 0) && (tp->wsz.ws_ypixel == 0)) { 936 miocnak(q, mp, 0, EINVAL); 937 return; 938 } 939 940 tmp = allocb(sizeof (struct winsize), BPRI_MED); 941 if (tmp == NULL) { 942 miocnak(q, mp, 0, EAGAIN); 943 return; 944 } 945 946 mioc2ack(mp, tmp, sizeof (struct winsize), 0); 947 948 wb = (struct winsize *)mp->b_cont->b_rptr; 949 wb->ws_row = tp->wsz.ws_row; 950 wb->ws_col = tp->wsz.ws_col; 951 wb->ws_xpixel = tp->wsz.ws_xpixel; 952 wb->ws_ypixel = tp->wsz.ws_ypixel; 953 954 qreply(q, mp); 955 return; 956 957 case TIOCSWINSZ: 958 error = miocpullup(mp, sizeof (struct winsize)); 959 if (error != 0) { 960 miocnak(q, mp, 0, error); 961 return; 962 } 963 964 wb = (struct winsize *)mp->b_cont->b_rptr; 965 /* 966 * Send a SIGWINCH signal if the row/col information has 967 * changed. 968 */ 969 if ((tp->wsz.ws_row != wb->ws_row) || 970 (tp->wsz.ws_col != wb->ws_col) || 971 (tp->wsz.ws_xpixel != wb->ws_xpixel) || 972 (tp->wsz.ws_ypixel != wb->ws_xpixel)) { 973 /* 974 * SIGWINCH is always sent upstream. 975 */ 976 if (qside == WRSIDE) 977 (void) putnextctl1(RD(q), M_SIG, SIGWINCH); 978 else if (qside == RDSIDE) 979 (void) putnextctl1(q, M_SIG, SIGWINCH); 980 /* 981 * Message may have come in as an M_IOCDATA; pass it 982 * to the master side as an M_IOCTL. 983 */ 984 mp->b_datap->db_type = M_IOCTL; 985 if (qside == WRSIDE) { 986 /* 987 * Need a copy of this message to pass on to 988 * the PCKT module, only if the M_IOCTL 989 * orginated from the slave side. 990 */ 991 if ((pckt_msgp = copymsg(mp)) == NULL) { 992 miocnak(q, mp, 0, EAGAIN); 993 return; 994 } 995 putnext(q, pckt_msgp); 996 } 997 tp->wsz.ws_row = wb->ws_row; 998 tp->wsz.ws_col = wb->ws_col; 999 tp->wsz.ws_xpixel = wb->ws_xpixel; 1000 tp->wsz.ws_ypixel = wb->ws_ypixel; 1001 } 1002 1003 mioc2ack(mp, NULL, 0, 0); 1004 qreply(q, mp); 1005 return; 1006 1007 case TIOCSIGNAL: { 1008 /* 1009 * This ioctl can emanate from the master side in remote 1010 * mode only. 1011 */ 1012 int sig; 1013 1014 if (DB_TYPE(mp) == M_IOCTL && iocp->ioc_count != TRANSPARENT) { 1015 error = miocpullup(mp, sizeof (int)); 1016 if (error != 0) { 1017 miocnak(q, mp, 0, error); 1018 return; 1019 } 1020 } 1021 1022 if (DB_TYPE(mp) == M_IOCDATA || iocp->ioc_count != TRANSPARENT) 1023 sig = *(int *)mp->b_cont->b_rptr; 1024 else 1025 sig = (int)*(intptr_t *)mp->b_cont->b_rptr; 1026 1027 if (sig < 1 || sig >= NSIG) { 1028 miocnak(q, mp, 0, EINVAL); 1029 return; 1030 } 1031 1032 /* 1033 * Send an M_PCSIG message up the slave's read side and 1034 * respond back to the master with an ACK or NAK as 1035 * appropriate. 1036 */ 1037 if (putnextctl1(q, M_PCSIG, sig) == 0) { 1038 miocnak(q, mp, 0, EAGAIN); 1039 return; 1040 } 1041 1042 mioc2ack(mp, NULL, 0, 0); 1043 qreply(q, mp); 1044 return; 1045 } 1046 1047 case TIOCREMOTE: { 1048 int onoff; 1049 mblk_t *mctlp; 1050 1051 if (DB_TYPE(mp) == M_IOCTL) { 1052 error = miocpullup(mp, sizeof (int)); 1053 if (error != 0) { 1054 miocnak(q, mp, 0, error); 1055 return; 1056 } 1057 } 1058 1059 onoff = *(int *)mp->b_cont->b_rptr; 1060 1061 /* 1062 * Send M_CTL up using the iocblk format. 1063 */ 1064 mctlp = mkiocb(onoff ? MC_NO_CANON : MC_DO_CANON); 1065 if (mctlp == NULL) { 1066 miocnak(q, mp, 0, EAGAIN); 1067 return; 1068 } 1069 mctlp->b_datap->db_type = M_CTL; 1070 putnext(q, mctlp); 1071 1072 /* 1073 * ACK the ioctl. 1074 */ 1075 mioc2ack(mp, NULL, 0, 0); 1076 qreply(q, mp); 1077 1078 /* 1079 * Record state change. 1080 */ 1081 if (onoff) 1082 tp->state |= REMOTEMODE; 1083 else 1084 tp->state &= ~REMOTEMODE; 1085 return; 1086 } 1087 1088 default: 1089 putnext(q, mp); 1090 return; 1091 } 1092 } 1093