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