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 #pragma ident "%Z%%M% %I% %E% SMI" /* from S5R4 1.13 */ 32 33 /* 34 * Description: 35 * 36 * The PTEM streams module is used as a pseudo driver emulator. Its purpose 37 * is to emulate the ioctl() functions of a terminal device driver. 38 */ 39 40 #include <sys/types.h> 41 #include <sys/param.h> 42 #include <sys/stream.h> 43 #include <sys/stropts.h> 44 #include <sys/strsun.h> 45 #include <sys/termio.h> 46 #include <sys/pcb.h> 47 #include <sys/signal.h> 48 #include <sys/cred.h> 49 #include <sys/strtty.h> 50 #include <sys/errno.h> 51 #include <sys/cmn_err.h> 52 #include <sys/jioctl.h> 53 #include <sys/ptem.h> 54 #include <sys/ptms.h> 55 #include <sys/debug.h> 56 #include <sys/kmem.h> 57 #include <sys/ddi.h> 58 #include <sys/sunddi.h> 59 #include <sys/conf.h> 60 #include <sys/modctl.h> 61 62 extern struct streamtab pteminfo; 63 64 static struct fmodsw fsw = { 65 "ptem", 66 &pteminfo, 67 D_MTQPAIR | D_MP 68 }; 69 70 static struct modlstrmod modlstrmod = { 71 &mod_strmodops, "pty hardware emulator", &fsw 72 }; 73 74 static struct modlinkage modlinkage = { 75 MODREV_1, &modlstrmod, NULL 76 }; 77 78 int 79 _init() 80 { 81 return (mod_install(&modlinkage)); 82 } 83 84 int 85 _fini() 86 { 87 return (mod_remove(&modlinkage)); 88 } 89 90 int 91 _info(struct modinfo *modinfop) 92 { 93 return (mod_info(&modlinkage, modinfop)); 94 } 95 96 /* 97 * stream data structure definitions 98 */ 99 static int ptemopen(queue_t *, dev_t *, int, int, cred_t *); 100 static int ptemclose(queue_t *, int, cred_t *); 101 static void ptemrput(queue_t *, mblk_t *); 102 static void ptemwput(queue_t *, mblk_t *); 103 static void ptemwsrv(queue_t *); 104 105 static struct module_info ptem_info = { 106 0xabcd, 107 "ptem", 108 0, 109 512, 110 512, 111 128 112 }; 113 114 static struct qinit ptemrinit = { 115 (int (*)()) ptemrput, 116 NULL, 117 ptemopen, 118 ptemclose, 119 NULL, 120 &ptem_info, 121 NULL 122 }; 123 124 static struct qinit ptemwinit = { 125 (int (*)()) ptemwput, 126 (int (*)()) ptemwsrv, 127 ptemopen, 128 ptemclose, 129 nulldev, 130 &ptem_info, 131 NULL 132 }; 133 134 struct streamtab pteminfo = { 135 &ptemrinit, 136 &ptemwinit, 137 NULL, 138 NULL 139 }; 140 141 static void ptioc(queue_t *, mblk_t *, int); 142 static int ptemwmsg(queue_t *, mblk_t *); 143 144 /* 145 * ptemopen - open routine gets called when the module gets pushed onto the 146 * stream. 147 */ 148 /* ARGSUSED */ 149 static int 150 ptemopen( 151 queue_t *q, /* pointer to the read side queue */ 152 dev_t *devp, /* pointer to stream tail's dev */ 153 int oflag, /* the user open(2) supplied flags */ 154 int sflag, /* open state flag */ 155 cred_t *credp) /* credentials */ 156 { 157 struct ptem *ntp; /* ptem entry for this PTEM module */ 158 mblk_t *mop; /* an setopts mblk */ 159 struct stroptions *sop; 160 struct termios *termiosp; 161 int len; 162 163 if (sflag != MODOPEN) 164 return (EINVAL); 165 166 if (q->q_ptr != NULL) { 167 /* It's already attached. */ 168 return (0); 169 } 170 171 /* 172 * Allocate state structure. 173 */ 174 ntp = kmem_alloc(sizeof (*ntp), KM_SLEEP); 175 176 /* 177 * Allocate a message block, used to pass the zero length message for 178 * "stty 0". 179 * 180 * NOTE: it's better to find out if such a message block can be 181 * allocated before it's needed than to not be able to 182 * deliver (for possible lack of buffers) when a hang-up 183 * occurs. 184 */ 185 if ((ntp->dack_ptr = allocb(4, BPRI_MED)) == NULL) { 186 kmem_free(ntp, sizeof (*ntp)); 187 return (EAGAIN); 188 } 189 190 /* 191 * Initialize an M_SETOPTS message to set up hi/lo water marks on 192 * stream head read queue and add controlling tty if not set. 193 */ 194 mop = allocb(sizeof (struct stroptions), BPRI_MED); 195 if (mop == NULL) { 196 freemsg(ntp->dack_ptr); 197 kmem_free(ntp, sizeof (*ntp)); 198 return (EAGAIN); 199 } 200 mop->b_datap->db_type = M_SETOPTS; 201 mop->b_wptr += sizeof (struct stroptions); 202 sop = (struct stroptions *)mop->b_rptr; 203 sop->so_flags = SO_HIWAT | SO_LOWAT | SO_ISTTY; 204 sop->so_hiwat = 512; 205 sop->so_lowat = 256; 206 207 /* 208 * Cross-link. 209 */ 210 ntp->q_ptr = q; 211 q->q_ptr = ntp; 212 WR(q)->q_ptr = ntp; 213 214 /* 215 * Get termios defaults. These are stored as 216 * a property in the "options" node. 217 */ 218 if (ddi_getlongprop(DDI_DEV_T_ANY, ddi_root_node(), 0, "ttymodes", 219 (caddr_t)&termiosp, &len) == DDI_PROP_SUCCESS && 220 len == sizeof (struct termios)) { 221 222 ntp->cflags = termiosp->c_cflag; 223 kmem_free(termiosp, len); 224 } else { 225 /* 226 * Gack! Whine about it. 227 */ 228 cmn_err(CE_WARN, "ptem: Couldn't get ttymodes property!"); 229 } 230 ntp->wsz.ws_row = 0; 231 ntp->wsz.ws_col = 0; 232 ntp->wsz.ws_xpixel = 0; 233 ntp->wsz.ws_ypixel = 0; 234 235 ntp->state = 0; 236 237 /* 238 * Commit to the open and send the M_SETOPTS off to the stream head. 239 */ 240 qprocson(q); 241 putnext(q, mop); 242 243 return (0); 244 } 245 246 247 /* 248 * ptemclose - This routine gets called when the module gets popped off of the 249 * stream. 250 */ 251 /* ARGSUSED */ 252 static int 253 ptemclose(queue_t *q, int flag, cred_t *credp) 254 { 255 struct ptem *ntp; /* ptem entry for this PTEM module */ 256 257 qprocsoff(q); 258 ntp = (struct ptem *)q->q_ptr; 259 freemsg(ntp->dack_ptr); 260 kmem_free(ntp, sizeof (*ntp)); 261 q->q_ptr = WR(q)->q_ptr = NULL; 262 return (0); 263 } 264 265 266 /* 267 * ptemrput - Module read queue put procedure. 268 * 269 * This is called from the module or driver downstream. 270 */ 271 static void 272 ptemrput(queue_t *q, mblk_t *mp) 273 { 274 struct iocblk *iocp; /* M_IOCTL data */ 275 struct copyresp *resp; /* transparent ioctl response struct */ 276 int error; 277 278 switch (mp->b_datap->db_type) { 279 case M_DELAY: 280 case M_READ: 281 freemsg(mp); 282 break; 283 284 case M_IOCTL: 285 iocp = (struct iocblk *)mp->b_rptr; 286 287 switch (iocp->ioc_cmd) { 288 case TCSBRK: 289 /* 290 * Send a break message upstream. 291 * 292 * XXX: Shouldn't the argument come into play in 293 * determining whether or not so send an M_BREAK? 294 * It certainly does in the write-side direction. 295 */ 296 error = miocpullup(mp, sizeof (int)); 297 if (error != 0) { 298 miocnak(q, mp, 0, error); 299 break; 300 } 301 if (!(*(int *)mp->b_cont->b_rptr)) { 302 if (!putnextctl(q, M_BREAK)) { 303 /* 304 * Send an NAK reply back 305 */ 306 miocnak(q, mp, 0, EAGAIN); 307 break; 308 } 309 } 310 /* 311 * ACK it. 312 */ 313 mioc2ack(mp, NULL, 0, 0); 314 qreply(q, mp); 315 break; 316 317 case JWINSIZE: 318 case TIOCGWINSZ: 319 case TIOCSWINSZ: 320 ptioc(q, mp, RDSIDE); 321 break; 322 323 case TIOCSIGNAL: 324 /* 325 * The following subtle logic is due to the fact that 326 * `mp' may be in any one of three distinct formats: 327 * 328 * 1. A transparent M_IOCTL with an intptr_t-sized 329 * payload containing the signal number. 330 * 331 * 2. An I_STR M_IOCTL with an int-sized payload 332 * containing the signal number. 333 * 334 * 3. An M_IOCDATA with an int-sized payload 335 * containing the signal number. 336 */ 337 if (iocp->ioc_count == TRANSPARENT) { 338 intptr_t sig = *(intptr_t *)mp->b_cont->b_rptr; 339 340 if (sig < 1 || sig >= NSIG) { 341 /* 342 * it's transparent with pointer 343 * to the arg 344 */ 345 mcopyin(mp, NULL, sizeof (int), NULL); 346 qreply(q, mp); 347 break; 348 } 349 } 350 ptioc(q, mp, RDSIDE); 351 break; 352 353 case TIOCREMOTE: 354 if (iocp->ioc_count != TRANSPARENT) 355 ptioc(q, mp, RDSIDE); 356 else { 357 mcopyin(mp, NULL, sizeof (int), NULL); 358 qreply(q, mp); 359 } 360 break; 361 362 default: 363 putnext(q, mp); 364 break; 365 } 366 break; 367 368 case M_IOCDATA: 369 resp = (struct copyresp *)mp->b_rptr; 370 if (resp->cp_rval) { 371 /* 372 * Just free message on failure. 373 */ 374 freemsg(mp); 375 break; 376 } 377 378 /* 379 * Only need to copy data for the SET case. 380 */ 381 switch (resp->cp_cmd) { 382 383 case TIOCSWINSZ: 384 case TIOCSIGNAL: 385 case TIOCREMOTE: 386 ptioc(q, mp, RDSIDE); 387 break; 388 389 case JWINSIZE: 390 case TIOCGWINSZ: 391 mp->b_datap->db_type = M_IOCACK; 392 mioc2ack(mp, NULL, 0, 0); 393 qreply(q, mp); 394 break; 395 396 default: 397 freemsg(mp); 398 break; 399 } 400 break; 401 402 case M_IOCACK: 403 case M_IOCNAK: 404 /* 405 * We only pass write-side ioctls through to the master that 406 * we've already ACKed or NAKed to the stream head. Thus, we 407 * discard ones arriving from below, since they're redundant 408 * from the point of view of modules above us. 409 */ 410 freemsg(mp); 411 break; 412 413 case M_HANGUP: 414 /* 415 * clear blocked state. 416 */ 417 { 418 struct ptem *ntp = (struct ptem *)q->q_ptr; 419 if (ntp->state & OFLOW_CTL) { 420 ntp->state &= ~OFLOW_CTL; 421 qenable(WR(q)); 422 } 423 } 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), 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 870 default: 871 putnext(q, mp); 872 break; 873 874 } 875 876 return (1); 877 } 878 879 /* 880 * Message must be of type M_IOCTL or M_IOCDATA for this routine to be called. 881 */ 882 static void 883 ptioc(queue_t *q, mblk_t *mp, int qside) 884 { 885 struct ptem *tp; 886 struct iocblk *iocp; 887 struct winsize *wb; 888 struct jwinsize *jwb; 889 mblk_t *tmp; 890 mblk_t *pckt_msgp; /* message sent to the PCKT module */ 891 int error; 892 893 iocp = (struct iocblk *)mp->b_rptr; 894 tp = (struct ptem *)q->q_ptr; 895 896 switch (iocp->ioc_cmd) { 897 898 case JWINSIZE: 899 /* 900 * For compatibility: If all zeros, NAK the message for dumb 901 * terminals. 902 */ 903 if ((tp->wsz.ws_row == 0) && (tp->wsz.ws_col == 0) && 904 (tp->wsz.ws_xpixel == 0) && (tp->wsz.ws_ypixel == 0)) { 905 miocnak(q, mp, 0, EINVAL); 906 return; 907 } 908 909 tmp = allocb(sizeof (struct jwinsize), BPRI_MED); 910 if (tmp == NULL) { 911 miocnak(q, mp, 0, EAGAIN); 912 return; 913 } 914 915 if (iocp->ioc_count == TRANSPARENT) 916 mcopyout(mp, NULL, sizeof (struct jwinsize), NULL, tmp); 917 else 918 mioc2ack(mp, tmp, sizeof (struct jwinsize), 0); 919 920 jwb = (struct jwinsize *)mp->b_cont->b_rptr; 921 jwb->bytesx = tp->wsz.ws_col; 922 jwb->bytesy = tp->wsz.ws_row; 923 jwb->bitsx = tp->wsz.ws_xpixel; 924 jwb->bitsy = tp->wsz.ws_ypixel; 925 926 qreply(q, mp); 927 return; 928 929 case TIOCGWINSZ: 930 /* 931 * If all zeros NAK the message for dumb terminals. 932 */ 933 if ((tp->wsz.ws_row == 0) && (tp->wsz.ws_col == 0) && 934 (tp->wsz.ws_xpixel == 0) && (tp->wsz.ws_ypixel == 0)) { 935 miocnak(q, mp, 0, EINVAL); 936 return; 937 } 938 939 tmp = allocb(sizeof (struct winsize), BPRI_MED); 940 if (tmp == NULL) { 941 miocnak(q, mp, 0, EAGAIN); 942 return; 943 } 944 945 mioc2ack(mp, tmp, sizeof (struct winsize), 0); 946 947 wb = (struct winsize *)mp->b_cont->b_rptr; 948 wb->ws_row = tp->wsz.ws_row; 949 wb->ws_col = tp->wsz.ws_col; 950 wb->ws_xpixel = tp->wsz.ws_xpixel; 951 wb->ws_ypixel = tp->wsz.ws_ypixel; 952 953 qreply(q, mp); 954 return; 955 956 case TIOCSWINSZ: 957 error = miocpullup(mp, sizeof (struct winsize)); 958 if (error != 0) { 959 miocnak(q, mp, 0, error); 960 return; 961 } 962 963 wb = (struct winsize *)mp->b_cont->b_rptr; 964 /* 965 * Send a SIGWINCH signal if the row/col information has 966 * changed. 967 */ 968 if ((tp->wsz.ws_row != wb->ws_row) || 969 (tp->wsz.ws_col != wb->ws_col) || 970 (tp->wsz.ws_xpixel != wb->ws_xpixel) || 971 (tp->wsz.ws_ypixel != wb->ws_xpixel)) { 972 /* 973 * SIGWINCH is always sent upstream. 974 */ 975 if (qside == WRSIDE) 976 (void) putnextctl1(RD(q), M_SIG, SIGWINCH); 977 else if (qside == RDSIDE) 978 (void) putnextctl1(q, M_SIG, SIGWINCH); 979 /* 980 * Message may have come in as an M_IOCDATA; pass it 981 * to the master side as an M_IOCTL. 982 */ 983 mp->b_datap->db_type = M_IOCTL; 984 if (qside == WRSIDE) { 985 /* 986 * Need a copy of this message to pass on to 987 * the PCKT module, only if the M_IOCTL 988 * orginated from the slave side. 989 */ 990 if ((pckt_msgp = copymsg(mp)) == NULL) { 991 miocnak(q, mp, 0, EAGAIN); 992 return; 993 } 994 putnext(q, pckt_msgp); 995 } 996 tp->wsz.ws_row = wb->ws_row; 997 tp->wsz.ws_col = wb->ws_col; 998 tp->wsz.ws_xpixel = wb->ws_xpixel; 999 tp->wsz.ws_ypixel = wb->ws_ypixel; 1000 } 1001 1002 mioc2ack(mp, NULL, 0, 0); 1003 qreply(q, mp); 1004 return; 1005 1006 case TIOCSIGNAL: { 1007 /* 1008 * This ioctl can emanate from the master side in remote 1009 * mode only. 1010 */ 1011 int sig; 1012 1013 if (DB_TYPE(mp) == M_IOCTL && iocp->ioc_count != TRANSPARENT) { 1014 error = miocpullup(mp, sizeof (int)); 1015 if (error != 0) { 1016 miocnak(q, mp, 0, error); 1017 return; 1018 } 1019 } 1020 1021 if (DB_TYPE(mp) == M_IOCDATA || iocp->ioc_count != TRANSPARENT) 1022 sig = *(int *)mp->b_cont->b_rptr; 1023 else 1024 sig = (int)*(intptr_t *)mp->b_cont->b_rptr; 1025 1026 if (sig < 1 || sig >= NSIG) { 1027 miocnak(q, mp, 0, EINVAL); 1028 return; 1029 } 1030 1031 /* 1032 * Send an M_PCSIG message up the slave's read side and 1033 * respond back to the master with an ACK or NAK as 1034 * appropriate. 1035 */ 1036 if (putnextctl1(q, M_PCSIG, sig) == 0) { 1037 miocnak(q, mp, 0, EAGAIN); 1038 return; 1039 } 1040 1041 mioc2ack(mp, NULL, 0, 0); 1042 qreply(q, mp); 1043 return; 1044 } 1045 1046 case TIOCREMOTE: { 1047 int onoff; 1048 mblk_t *mctlp; 1049 1050 if (DB_TYPE(mp) == M_IOCTL) { 1051 error = miocpullup(mp, sizeof (int)); 1052 if (error != 0) { 1053 miocnak(q, mp, 0, error); 1054 return; 1055 } 1056 } 1057 1058 onoff = *(int *)mp->b_cont->b_rptr; 1059 1060 /* 1061 * Send M_CTL up using the iocblk format. 1062 */ 1063 mctlp = mkiocb(onoff ? MC_NO_CANON : MC_DO_CANON); 1064 if (mctlp == NULL) { 1065 miocnak(q, mp, 0, EAGAIN); 1066 return; 1067 } 1068 mctlp->b_datap->db_type = M_CTL; 1069 putnext(q, mctlp); 1070 1071 /* 1072 * ACK the ioctl. 1073 */ 1074 mioc2ack(mp, NULL, 0, 0); 1075 qreply(q, mp); 1076 1077 /* 1078 * Record state change. 1079 */ 1080 if (onoff) 1081 tp->state |= REMOTEMODE; 1082 else 1083 tp->state &= ~REMOTEMODE; 1084 return; 1085 } 1086 1087 default: 1088 putnext(q, mp); 1089 return; 1090 } 1091 } 1092