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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 * Copyright 2018 OmniOS Community Edition (OmniOSce) Association. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 /* 31 * University Copyright- Copyright (c) 1982, 1986, 1988 32 * The Regents of the University of California 33 * All Rights Reserved 34 * 35 * University Acknowledgment- Portions of this document are derived from 36 * software developed by the University of California, Berkeley, and its 37 * contributors. 38 */ 39 40 /* 41 * Module to intercept old V7 and 4BSD "ioctl" calls. 42 */ 43 44 #include <sys/types.h> 45 #include <sys/param.h> 46 #include <sys/signal.h> 47 #include <sys/file.h> 48 #include <sys/termios.h> 49 #include <sys/ttold.h> 50 #include <sys/cmn_err.h> 51 #include <sys/stream.h> 52 #include <sys/stropts.h> 53 #include <sys/strsubr.h> 54 #include <sys/strsun.h> 55 #include <sys/errno.h> 56 #include <sys/debug.h> 57 #include <sys/ttcompat.h> 58 #include <sys/ddi.h> 59 #include <sys/sunddi.h> 60 #include <sys/kmem.h> 61 #include <sys/policy.h> 62 63 /* 64 * This is the loadable module wrapper. 65 */ 66 #include <sys/conf.h> 67 #include <sys/modctl.h> 68 69 /* See os/streamio.c */ 70 extern int sgttyb_handling; 71 72 static struct streamtab ttcoinfo; 73 74 static struct fmodsw fsw = { 75 "ttcompat", 76 &ttcoinfo, 77 D_MTQPAIR | D_MP | _D_SINGLE_INSTANCE 78 }; 79 80 /* 81 * Module linkage information for the kernel. 82 */ 83 84 static struct modlstrmod modlstrmod = { 85 &mod_strmodops, 86 "alt ioctl calls", 87 &fsw 88 }; 89 90 static struct modlinkage modlinkage = { 91 MODREV_1, &modlstrmod, NULL 92 }; 93 94 int 95 _init(void) 96 { 97 return (mod_install(&modlinkage)); 98 } 99 100 int 101 _fini(void) 102 { 103 return (mod_remove(&modlinkage)); 104 } 105 106 int 107 _info(struct modinfo *modinfop) 108 { 109 return (mod_info(&modlinkage, modinfop)); 110 } 111 112 static int ttcompatopen(queue_t *, dev_t *, int, int, cred_t *); 113 static int ttcompatclose(queue_t *, int, cred_t *); 114 static void ttcompatrput(queue_t *, mblk_t *); 115 static void ttcompatwput(queue_t *, mblk_t *); 116 117 static struct module_info ttycompatmiinfo = { 118 0, 119 "ttcompat", 120 0, 121 INFPSZ, 122 2048, 123 128 124 }; 125 126 static struct qinit ttycompatrinit = { 127 (int (*)())ttcompatrput, 128 NULL, 129 ttcompatopen, 130 ttcompatclose, 131 NULL, 132 &ttycompatmiinfo 133 }; 134 135 static struct module_info ttycompatmoinfo = { 136 42, 137 "ttcompat", 138 0, 139 INFPSZ, 140 300, 141 200 142 }; 143 144 static struct qinit ttycompatwinit = { 145 (int (*)())ttcompatwput, 146 NULL, 147 ttcompatopen, 148 ttcompatclose, 149 NULL, 150 &ttycompatmoinfo 151 }; 152 153 static struct streamtab ttcoinfo = { 154 &ttycompatrinit, 155 &ttycompatwinit, 156 NULL, 157 NULL 158 }; 159 160 static void ttcompat_do_ioctl(ttcompat_state_t *, queue_t *, mblk_t *); 161 static void ttcompat_ioctl_ack(queue_t *, mblk_t *); 162 static void ttcopyout(queue_t *, mblk_t *); 163 static void ttcompat_ioctl_nak(queue_t *, mblk_t *); 164 static void from_compat(compat_state_t *, struct termios *); 165 static void to_compat(struct termios *, compat_state_t *); 166 167 /* 168 * Open - get the current modes and translate them to the V7/4BSD equivalent. 169 */ 170 /*ARGSUSED*/ 171 static int 172 ttcompatopen(queue_t *q, dev_t *devp, int oflag, int sflag, cred_t *crp) 173 { 174 ttcompat_state_t *tp; 175 176 if (q->q_ptr != NULL) { 177 tp = (ttcompat_state_t *)q->q_ptr; 178 /* fail open if TIOCEXCL was done and its not privileged */ 179 if ((tp->t_new_lflags & XCLUDE) && 180 secpolicy_excl_open(crp) != 0) { 181 return (EBUSY); 182 } 183 return (0); /* already attached */ 184 } 185 tp = kmem_zalloc(sizeof (ttcompat_state_t), KM_SLEEP); 186 q->q_ptr = tp; 187 WR(q)->q_ptr = tp; 188 qprocson(q); 189 190 return (0); 191 } 192 193 /* ARGSUSED1 */ 194 static int 195 ttcompatclose(queue_t *q, int flag, cred_t *crp) 196 { 197 ttcompat_state_t *tp = (ttcompat_state_t *)q->q_ptr; 198 mblk_t *mp; 199 200 /* Dump the state structure, then unlink it */ 201 qprocsoff(q); 202 if (tp->t_bufcallid != 0) { 203 qunbufcall(q, tp->t_bufcallid); 204 tp->t_bufcallid = 0; 205 } 206 if ((mp = tp->t_iocpending) != NULL) 207 freemsg(mp); 208 kmem_free(tp, sizeof (ttcompat_state_t)); 209 q->q_ptr = NULL; 210 211 return (0); 212 } 213 214 /* 215 * Put procedure for input from driver end of stream (read queue). 216 * Most messages just get passed to the next guy up; we intercept 217 * "ioctl" replies, and if it's an "ioctl" whose reply we plan to do 218 * something with, we do it. 219 */ 220 static void 221 ttcompatrput(queue_t *q, mblk_t *mp) 222 { 223 switch (mp->b_datap->db_type) { 224 225 case M_IOCACK: 226 ttcompat_ioctl_ack(q, mp); 227 break; 228 229 case M_IOCNAK: 230 ttcompat_ioctl_nak(q, mp); 231 break; 232 233 default: 234 putnext(q, mp); 235 break; 236 } 237 } 238 239 /* 240 * Line discipline output queue put procedure: speeds M_IOCTL 241 * messages. 242 */ 243 static void 244 ttcompatwput(queue_t *q, mblk_t *mp) 245 { 246 ttcompat_state_t *tp; 247 struct copyreq *cqp; 248 struct copyresp *csp; 249 struct iocblk *iocbp; 250 251 tp = (ttcompat_state_t *)q->q_ptr; 252 253 /* 254 * Process some M_IOCTL messages here; pass everything else down. 255 */ 256 switch (mp->b_datap->db_type) { 257 258 default: 259 putnext(q, mp); 260 return; 261 262 case M_IOCTL: 263 iocbp = (struct iocblk *)mp->b_rptr; 264 265 switch (iocbp->ioc_cmd) { 266 267 default: 268 /* these are ioctls with no arguments or are known to stream head */ 269 /* process them right away */ 270 ttcompat_do_ioctl(tp, q, mp); 271 return; 272 case TIOCSETN: 273 case TIOCSLTC: 274 case TIOCSETC: 275 case TIOCLBIS: 276 case TIOCLBIC: 277 case TIOCLSET: 278 case TIOCFLUSH: 279 if (iocbp->ioc_count != TRANSPARENT) { 280 putnext(q, mp); 281 return; 282 } 283 284 mp->b_datap->db_type = M_COPYIN; 285 cqp = (struct copyreq *)mp->b_rptr; 286 cqp->cq_addr = (caddr_t)*(intptr_t *)mp->b_cont->b_rptr; 287 switch (iocbp->ioc_cmd) { 288 case TIOCSETN: 289 cqp->cq_size = sizeof (struct sgttyb); 290 break; 291 case TIOCSLTC: 292 cqp->cq_size = sizeof (struct ltchars); 293 break; 294 case TIOCSETC: 295 cqp->cq_size = sizeof (struct tchars); 296 break; 297 case TIOCLBIS: 298 case TIOCLBIC: 299 case TIOCLSET: 300 case TIOCFLUSH: 301 cqp->cq_size = sizeof (int); 302 break; 303 default: 304 break; 305 } 306 cqp->cq_flag = 0; 307 cqp->cq_private = NULL; 308 freemsg(mp->b_cont); 309 mp->b_cont = NULL; 310 mp->b_wptr = mp->b_rptr + sizeof (struct copyreq); 311 tp->t_ioccmd = iocbp->ioc_cmd; 312 tp->t_state |= TS_W_IN; 313 qreply(q, mp); 314 return; 315 316 } /* switch ioc_cmd */ 317 case M_IOCDATA: 318 csp = (struct copyresp *)mp->b_rptr; 319 320 switch (csp->cp_cmd) { 321 322 default: 323 putnext(q, mp); 324 return; 325 326 case TIOCSETN: 327 case TIOCSLTC: 328 case TIOCSETC: 329 case TIOCLBIS: 330 case TIOCLBIC: 331 case TIOCLSET: 332 case TIOCFLUSH: 333 tp->t_state &= ~TS_W_IN; 334 if (csp->cp_rval != 0) { /* failure */ 335 freemsg(mp); 336 return; 337 } 338 339 /* make it look like an ioctl */ 340 mp->b_datap->db_type = M_IOCTL; 341 mp->b_wptr = mp->b_rptr + sizeof (struct iocblk); 342 iocbp = (struct iocblk *)mp->b_rptr; 343 iocbp->ioc_count = MBLKL(mp->b_cont); 344 iocbp->ioc_error = 0; 345 iocbp->ioc_rval = 0; 346 ttcompat_do_ioctl(tp, q, mp); 347 return; 348 349 case TIOCGLTC: 350 case TIOCLGET: 351 case TIOCGETC: 352 tp->t_state &= ~TS_W_OUT; 353 if (csp->cp_rval != 0) { /* failure */ 354 freemsg(mp); 355 return; 356 } 357 358 iocbp = (struct iocblk *)mp->b_rptr; 359 iocbp->ioc_count = 0; 360 iocbp->ioc_error = 0; 361 iocbp->ioc_rval = 0; 362 mp->b_datap->db_type = M_IOCACK; 363 qreply(q, mp); 364 return; 365 366 } /* switch cp_cmd */ 367 } /* end message switch */ 368 } 369 370 /* 371 * Retry an "ioctl", now that "bufcall" claims we may be able to allocate 372 * the buffer we need. 373 */ 374 static void 375 ttcompat_reioctl(void *arg) 376 { 377 queue_t *q = arg; 378 ttcompat_state_t *tp; 379 mblk_t *mp; 380 381 tp = (ttcompat_state_t *)q->q_ptr; 382 tp->t_bufcallid = 0; 383 384 if ((mp = tp->t_iocpending) != NULL) { 385 tp->t_iocpending = NULL; /* not pending any more */ 386 ttcompat_do_ioctl(tp, q, mp); 387 } 388 } 389 390 /* 391 * Handle old-style "ioctl" messages; pass the rest down unmolested. 392 */ 393 static void 394 ttcompat_do_ioctl(ttcompat_state_t *tp, queue_t *q, mblk_t *mp) 395 { 396 struct iocblk *iocp; 397 int error; 398 399 /* 400 * Most of the miocpullup()'s below aren't needed because the 401 * ioctls in question are actually transparent M_IOCDATA messages 402 * dummied to look like M_IOCTL messages. However, for clarity and 403 * robustness against future changes, we've included them anyway. 404 */ 405 406 iocp = (struct iocblk *)mp->b_rptr; 407 switch (iocp->ioc_cmd) { 408 409 /* 410 * "get"-style calls that get translated data from the "termios" 411 * structure. Save the existing code and pass it down as a TCGETS. 412 */ 413 case TIOCGETC: 414 case TIOCLGET: 415 case TIOCGLTC: 416 if (iocp->ioc_count != TRANSPARENT) { 417 miocnak(q, mp, 0, EINVAL); 418 return; 419 } 420 421 /* 422 * We can get here with t_arg != 0, iff the stream head 423 * has for some reason given up on the ioctl in progress. 424 * The most likely cause is an interrupted ioctl syscall. 425 * We will behave robustly because (given our perimeter) 426 * the ttcompat_state_t will get set up for the new ioctl, 427 * and when the response we were waiting for appears it 428 * will be passed on to the stream head which will discard 429 * it as non-current. 430 */ 431 ASSERT(mp->b_cont != NULL); 432 tp->t_arg = *(intptr_t *)mp->b_cont->b_rptr; 433 /* free the data buffer - it might not be sufficient */ 434 /* driver will allocate one for termios size */ 435 freemsg(mp->b_cont); 436 mp->b_cont = NULL; 437 iocp->ioc_count = 0; 438 /* FALLTHRU */ 439 case TIOCGETP: 440 goto dogets; 441 442 /* 443 * "set"-style calls that set translated data into a "termios" 444 * structure. Set our idea of the new state from the value 445 * given to us. We then have to get the current state, so we 446 * turn this guy into a TCGETS and pass it down. When the 447 * ACK comes back, we modify the state we got back and shove it 448 * back down as the appropriate type of TCSETS. 449 */ 450 case TIOCSETP: 451 case TIOCSETN: 452 error = miocpullup(mp, sizeof (struct sgttyb)); 453 if (error != 0) { 454 miocnak(q, mp, 0, error); 455 return; 456 } 457 tp->t_new_sgttyb = *((struct sgttyb *)mp->b_cont->b_rptr); 458 goto dogets; 459 460 case TIOCSETC: 461 error = miocpullup(mp, sizeof (struct tchars)); 462 if (error != 0) { 463 miocnak(q, mp, 0, error); 464 return; 465 } 466 tp->t_new_tchars = *((struct tchars *)mp->b_cont->b_rptr); 467 goto dogets; 468 469 case TIOCSLTC: 470 error = miocpullup(mp, sizeof (struct ltchars)); 471 if (error != 0) { 472 miocnak(q, mp, 0, error); 473 return; 474 } 475 tp->t_new_ltchars = *((struct ltchars *)mp->b_cont->b_rptr); 476 goto dogets; 477 478 case TIOCLBIS: 479 case TIOCLBIC: 480 case TIOCLSET: 481 error = miocpullup(mp, sizeof (int)); 482 if (error != 0) { 483 miocnak(q, mp, 0, error); 484 return; 485 } 486 tp->t_new_lflags = *(int *)mp->b_cont->b_rptr; 487 goto dogets; 488 489 /* 490 * "set"-style call that sets a particular bit in a "termios" 491 * structure. We then have to get the current state, so we 492 * turn this guy into a TCGETS and pass it down. When the 493 * ACK comes back, we modify the state we got back and shove it 494 * back down as the appropriate type of TCSETS. 495 */ 496 case TIOCHPCL: 497 dogets: 498 tp->t_ioccmd = iocp->ioc_cmd; 499 tp->t_iocid = iocp->ioc_id; 500 tp->t_state |= TS_IOCWAIT; 501 iocp->ioc_cmd = TCGETS; 502 iocp->ioc_count = 0; /* no data returned unless we say so */ 503 break; 504 505 /* 506 * "set"-style call that sets DTR. Pretend that it was a TIOCMBIS 507 * with TIOCM_DTR set. 508 */ 509 case TIOCSDTR: { 510 mblk_t *datap; 511 512 if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) 513 goto allocfailure; 514 *(int *)datap->b_wptr = TIOCM_DTR; 515 datap->b_wptr += sizeof (int); 516 iocp->ioc_cmd = TIOCMBIS; /* turn it into a TIOCMBIS */ 517 if (mp->b_cont != NULL) 518 freemsg(mp->b_cont); 519 mp->b_cont = datap; /* attach the data */ 520 iocp->ioc_count = sizeof (int); /* in case driver checks */ 521 break; 522 } 523 524 /* 525 * "set"-style call that clears DTR. Pretend that it was a TIOCMBIC 526 * with TIOCM_DTR set. 527 */ 528 case TIOCCDTR: { 529 mblk_t *datap; 530 531 if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) 532 goto allocfailure; 533 *(int *)datap->b_wptr = TIOCM_DTR; 534 datap->b_wptr += sizeof (int); 535 iocp->ioc_cmd = TIOCMBIC; /* turn it into a TIOCMBIC */ 536 if (mp->b_cont != NULL) 537 freemsg(mp->b_cont); 538 mp->b_cont = datap; /* attach the data */ 539 iocp->ioc_count = sizeof (int); /* in case driver checks */ 540 break; 541 } 542 543 /* 544 * Translate into the S5 form of TCFLSH. 545 */ 546 case TIOCFLUSH: { 547 int flags; 548 549 error = miocpullup(mp, sizeof (int)); 550 if (error != 0) { 551 miocnak(q, mp, 0, error); 552 return; 553 } 554 flags = *(int *)mp->b_cont->b_rptr; 555 556 switch (flags&(FREAD|FWRITE)) { 557 558 case 0: 559 case FREAD|FWRITE: 560 flags = 2; /* flush 'em both */ 561 break; 562 563 case FREAD: 564 flags = 0; /* flush read */ 565 break; 566 567 case FWRITE: 568 flags = 1; /* flush write */ 569 break; 570 } 571 iocp->ioc_cmd = TCFLSH; /* turn it into a TCFLSH */ 572 *(int *)mp->b_cont->b_rptr = flags; /* fiddle the arg */ 573 break; 574 } 575 576 /* 577 * Turn into a TCXONC. 578 */ 579 case TIOCSTOP: { 580 mblk_t *datap; 581 582 if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) 583 goto allocfailure; 584 *(int *)datap->b_wptr = 0; /* stop */ 585 datap->b_wptr += sizeof (int); 586 iocp->ioc_cmd = TCXONC; /* turn it into a XONC */ 587 iocp->ioc_count = sizeof (int); 588 if (mp->b_cont != NULL) 589 freemsg(mp->b_cont); 590 mp->b_cont = datap; /* attach the data */ 591 break; 592 } 593 594 case TIOCSTART: { 595 mblk_t *datap; 596 597 if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) 598 goto allocfailure; 599 *(int *)datap->b_wptr = 1; /* start */ 600 datap->b_wptr += sizeof (int); 601 iocp->ioc_cmd = TCXONC; /* turn it into a XONC */ 602 iocp->ioc_count = sizeof (int); 603 if (mp->b_cont != NULL) 604 freemsg(mp->b_cont); 605 mp->b_cont = datap; /* attach the data */ 606 break; 607 } 608 case TIOCSETD: 609 case TIOCGETD: 610 case DIOCSETP: 611 case DIOCGETP: 612 case LDOPEN: 613 case LDCLOSE: 614 case LDCHG: 615 case LDSETT: 616 case LDGETT: 617 /* 618 * All of these ioctls are just ACK'd, except for 619 * TIOCSETD, which must be for line discipline zero. 620 */ 621 mp->b_datap->db_type = M_IOCACK; 622 if (iocp->ioc_cmd == TIOCSETD) { 623 iocp->ioc_error = miocpullup(mp, sizeof (uchar_t)); 624 if (iocp->ioc_error == 0 && (*mp->b_cont->b_rptr != 0)) 625 mp->b_datap->db_type = M_IOCNAK; 626 } 627 628 iocp->ioc_error = 0; 629 iocp->ioc_count = 0; 630 iocp->ioc_rval = 0; 631 qreply(q, mp); 632 return; 633 case IOCTYPE: 634 mp->b_datap->db_type = M_IOCACK; 635 iocp->ioc_error = 0; 636 iocp->ioc_count = 0; 637 iocp->ioc_rval = TIOC; 638 qreply(q, mp); 639 return; 640 case TIOCEXCL: 641 /* check for binary value of XCLUDE flag ???? */ 642 tp->t_new_lflags |= XCLUDE; 643 mp->b_datap->db_type = M_IOCACK; 644 iocp->ioc_error = 0; 645 iocp->ioc_count = 0; 646 iocp->ioc_rval = 0; 647 qreply(q, mp); 648 return; 649 case TIOCNXCL: 650 tp->t_new_lflags &= ~XCLUDE; 651 mp->b_datap->db_type = M_IOCACK; 652 iocp->ioc_error = 0; 653 iocp->ioc_count = 0; 654 iocp->ioc_rval = 0; 655 qreply(q, mp); 656 return; 657 } 658 659 /* 660 * We don't reply to most calls, we just pass them down, 661 * possibly after modifying the arguments. 662 */ 663 putnext(q, mp); 664 return; 665 666 allocfailure: 667 /* 668 * We needed to allocate something to handle this "ioctl", but 669 * couldn't; save this "ioctl" and arrange to get called back when 670 * it's more likely that we can get what we need. 671 * If there's already one being saved, throw it out, since it 672 * must have timed out. 673 */ 674 if (tp->t_iocpending != NULL) 675 freemsg(tp->t_iocpending); 676 tp->t_iocpending = mp; /* hold this ioctl */ 677 if (tp->t_bufcallid != 0) 678 qunbufcall(q, tp->t_bufcallid); 679 680 tp->t_bufcallid = qbufcall(q, sizeof (struct iocblk), BPRI_HI, 681 ttcompat_reioctl, q); 682 } 683 684 /* 685 * Called when an M_IOCACK message is seen on the read queue; if this 686 * is the response we were waiting for, we either: 687 * modify the data going up (if the "ioctl" read data); since in all 688 * cases, the old-style returned information is smaller than or the same 689 * size as the new-style returned information, we just overwrite the old 690 * stuff with the new stuff (beware of changing structure sizes, in case 691 * you invalidate this) 692 * or 693 * take this data, modify it appropriately, and send it back down (if 694 * the "ioctl" wrote data). 695 * In either case, we cancel the "wait"; the final response to a "write" 696 * ioctl goes back up to the user. 697 * If this wasn't the response we were waiting for, just pass it up. 698 */ 699 static void 700 ttcompat_ioctl_ack(queue_t *q, mblk_t *mp) 701 { 702 ttcompat_state_t *tp; 703 struct iocblk *iocp; 704 mblk_t *datap; 705 706 tp = (ttcompat_state_t *)q->q_ptr; 707 iocp = (struct iocblk *)mp->b_rptr; 708 709 if (!(tp->t_state&TS_IOCWAIT) || iocp->ioc_id != tp->t_iocid) { 710 /* 711 * This isn't the reply we're looking for. Move along. 712 */ 713 putnext(q, mp); 714 return; 715 } 716 717 datap = mp->b_cont; /* mblk containing data going up */ 718 719 switch (tp->t_ioccmd) { 720 721 case TIOCGETP: { 722 struct sgttyb *cb; 723 724 to_compat((struct termios *)datap->b_rptr, &tp->t_curstate); 725 datap->b_rptr = datap->b_wptr = datap->b_datap->db_base; 726 /* recycle the reply's buffer */ 727 cb = (struct sgttyb *)datap->b_wptr; 728 /* 729 * This is used for TIOCGETP handling of sg_ispeed and 730 * sg_ospeed. If the current speed is over 38400 (the 731 * sgttyb limit), then we report 38400. Note that 732 * when "compatibility with old releases" is enabled 733 * (sgttyb_handling == 0), then t_[io]speed will have 734 * garbled nonsense, as in prior releases. (See 735 * to_compat() below). 736 */ 737 cb->sg_ispeed = tp->t_curstate.t_ispeed > B38400 ? B38400 : 738 tp->t_curstate.t_ispeed; 739 cb->sg_ospeed = tp->t_curstate.t_ospeed > B38400 ? B38400 : 740 tp->t_curstate.t_ospeed; 741 cb->sg_erase = tp->t_curstate.t_erase; 742 cb->sg_kill = tp->t_curstate.t_kill; 743 cb->sg_flags = tp->t_curstate.t_flags; 744 datap->b_wptr += sizeof (struct sgttyb); 745 iocp->ioc_count = sizeof (struct sgttyb); 746 747 /* you are lucky - stream head knows how to copy you out */ 748 749 tp->t_state &= ~TS_IOCWAIT; /* we got what we wanted */ 750 iocp->ioc_rval = 0; 751 iocp->ioc_cmd = tp->t_ioccmd; 752 putnext(q, mp); 753 return; 754 } 755 756 case TIOCGETC: 757 to_compat((struct termios *)datap->b_rptr, &tp->t_curstate); 758 datap->b_rptr = datap->b_wptr = datap->b_datap->db_base; 759 /* recycle the reply's buffer */ 760 bcopy(&tp->t_curstate.t_intrc, datap->b_wptr, 761 sizeof (struct tchars)); 762 datap->b_wptr += sizeof (struct tchars); 763 break; 764 765 case TIOCGLTC: 766 to_compat((struct termios *)datap->b_rptr, &tp->t_curstate); 767 datap->b_rptr = datap->b_wptr = datap->b_datap->db_base; 768 /* recycle the reply's buffer */ 769 bcopy(&tp->t_curstate.t_suspc, datap->b_wptr, 770 sizeof (struct ltchars)); 771 datap->b_wptr += sizeof (struct ltchars); 772 break; 773 774 case TIOCLGET: 775 to_compat((struct termios *)datap->b_rptr, &tp->t_curstate); 776 datap->b_rptr = datap->b_wptr = datap->b_datap->db_base; 777 /* recycle the reply's buffer */ 778 *(int *)datap->b_wptr = 779 ((unsigned)tp->t_curstate.t_flags) >> 16; 780 datap->b_wptr += sizeof (int); 781 break; 782 783 case TIOCSETP: 784 case TIOCSETN: 785 /* 786 * Get the current state from the GETS data, and 787 * update it. 788 */ 789 to_compat((struct termios *)datap->b_rptr, &tp->t_curstate); 790 tp->t_curstate.t_erase = tp->t_new_sgttyb.sg_erase; 791 tp->t_curstate.t_kill = tp->t_new_sgttyb.sg_kill; 792 /* 793 * For new-style handling, we ignore requests to set 794 * B38400 when the current speed is over B38400. This 795 * means that we change the speed as requested if: 796 * old style (sgttyb_handling == 0) is requested 797 * the requested new speed isn't B38400 798 * the current speed is at or below B38400 799 * Note that when old style is requested, both speeds 800 * in t_curstate are set to <= B38400 by to_compat, so 801 * the first test isn't needed here. 802 * Also note that we silently allow the user to set 803 * speeds above B38400 through this interface, 804 * regardless of the style setting. This allows 805 * greater compatibility with current BSD releases. 806 */ 807 if (tp->t_new_sgttyb.sg_ispeed != B38400 || 808 tp->t_curstate.t_ispeed <= B38400) 809 tp->t_curstate.t_ispeed = tp->t_new_sgttyb.sg_ispeed; 810 if (tp->t_new_sgttyb.sg_ospeed != B38400 || 811 tp->t_curstate.t_ospeed <= B38400) 812 tp->t_curstate.t_ospeed = tp->t_new_sgttyb.sg_ospeed; 813 tp->t_curstate.t_flags = 814 (tp->t_curstate.t_flags & 0xffff0000) | 815 (tp->t_new_sgttyb.sg_flags & 0xffff); 816 817 /* 818 * Replace the data that came up with the updated data. 819 */ 820 from_compat(&tp->t_curstate, (struct termios *)datap->b_rptr); 821 822 /* 823 * Send it back down as a TCSETS or TCSETSF. 824 */ 825 iocp->ioc_cmd = (tp->t_ioccmd == TIOCSETP) ? TCSETSF : TCSETS; 826 goto senddown; 827 828 case TIOCSETC: 829 /* 830 * Get the current state from the GETS data, and 831 * update it. 832 */ 833 to_compat((struct termios *)datap->b_rptr, &tp->t_curstate); 834 bcopy(&tp->t_new_tchars, 835 &tp->t_curstate.t_intrc, sizeof (struct tchars)); 836 837 /* 838 * Replace the data that came up with the updated data. 839 */ 840 from_compat(&tp->t_curstate, (struct termios *)datap->b_rptr); 841 842 /* 843 * Send it back down as a TCSETS. 844 */ 845 iocp->ioc_cmd = TCSETS; 846 goto senddown; 847 848 case TIOCSLTC: 849 /* 850 * Get the current state from the GETS data, and 851 * update it. 852 */ 853 to_compat((struct termios *)datap->b_rptr, &tp->t_curstate); 854 bcopy(&tp->t_new_ltchars, 855 &tp->t_curstate.t_suspc, sizeof (struct ltchars)); 856 857 /* 858 * Replace the data that came up with the updated data. 859 */ 860 from_compat(&tp->t_curstate, (struct termios *)datap->b_rptr); 861 862 /* 863 * Send it back down as a TCSETS. 864 */ 865 iocp->ioc_cmd = TCSETS; 866 goto senddown; 867 868 case TIOCLBIS: 869 /* 870 * Get the current state from the GETS data, and 871 * update it. 872 */ 873 to_compat((struct termios *)datap->b_rptr, &tp->t_curstate); 874 tp->t_curstate.t_flags |= (tp->t_new_lflags << 16); 875 876 /* 877 * Replace the data that came up with the updated data. 878 */ 879 from_compat(&tp->t_curstate, (struct termios *)datap->b_rptr); 880 881 /* 882 * Send it back down as a TCSETS. 883 */ 884 iocp->ioc_cmd = TCSETS; 885 goto senddown; 886 887 case TIOCLBIC: 888 /* 889 * Get the current state from the GETS data, and 890 * update it. 891 */ 892 to_compat((struct termios *)datap->b_rptr, &tp->t_curstate); 893 tp->t_curstate.t_flags &= ~(tp->t_new_lflags << 16); 894 895 /* 896 * Replace the data that came up with the updated data. 897 */ 898 from_compat(&tp->t_curstate, (struct termios *)datap->b_rptr); 899 900 /* 901 * Send it back down as a TCSETS. 902 */ 903 iocp->ioc_cmd = TCSETS; 904 goto senddown; 905 906 case TIOCLSET: 907 /* 908 * Get the current state from the GETS data, and 909 * update it. 910 */ 911 to_compat((struct termios *)datap->b_rptr, &tp->t_curstate); 912 tp->t_curstate.t_flags &= 0xffff; 913 tp->t_curstate.t_flags |= (tp->t_new_lflags << 16); 914 915 /* 916 * Replace the data that came up with the updated data. 917 */ 918 from_compat(&tp->t_curstate, (struct termios *)datap->b_rptr); 919 920 /* 921 * Send it back down as a TCSETS. 922 */ 923 iocp->ioc_cmd = TCSETS; 924 goto senddown; 925 926 case TIOCHPCL: 927 /* 928 * Replace the data that came up with the updated data. 929 */ 930 ((struct termios *)datap->b_rptr)->c_cflag |= HUPCL; 931 932 /* 933 * Send it back down as a TCSETS. 934 */ 935 iocp->ioc_cmd = TCSETS; 936 goto senddown; 937 938 case TCSETSF: 939 /* 940 * We're acknowledging the terminal reset ioctl that we sent 941 * when the module was opened. 942 */ 943 tp->t_state &= ~(TS_IOCWAIT | TS_TIOCNAK); 944 freemsg(mp); 945 return; 946 947 default: 948 cmn_err(CE_WARN, "ttcompat: Unexpected ioctl acknowledgment\n"); 949 } 950 951 /* 952 * All the calls that return something return 0. 953 */ 954 tp->t_state &= ~TS_IOCWAIT; /* we got what we wanted */ 955 iocp->ioc_rval = 0; 956 957 /* copy out the data - ioctl transparency */ 958 iocp->ioc_cmd = tp->t_ioccmd; 959 ttcopyout(q, mp); 960 return; 961 962 senddown: 963 /* 964 * Send a "get state" reply back down, with suitably-modified 965 * state, as a "set state" "ioctl". 966 */ 967 tp->t_state &= ~TS_IOCWAIT; 968 mp->b_datap->db_type = M_IOCTL; 969 mp->b_wptr = mp->b_rptr + sizeof (struct iocblk); 970 putnext(WR(q), mp); 971 } 972 /* Called from ttcompatrput M_IOCACK processing. */ 973 /* Copies out the data using M_COPYOUT messages */ 974 975 static void 976 ttcopyout(queue_t *q, mblk_t *mp) 977 { 978 struct copyreq *cqp; 979 ttcompat_state_t *tp; 980 981 tp = (ttcompat_state_t *)q->q_ptr; 982 983 mp->b_datap->db_type = M_COPYOUT; 984 cqp = (struct copyreq *)mp->b_rptr; 985 cqp->cq_addr = (caddr_t)tp->t_arg; /* retrieve the 3rd argument */ 986 tp->t_arg = 0; /* clear it since we don't need it anymore */ 987 switch (tp->t_ioccmd) { 988 case TIOCGLTC: 989 cqp->cq_size = sizeof (struct ltchars); 990 break; 991 case TIOCGETC: 992 cqp->cq_size = sizeof (struct tchars); 993 break; 994 case TIOCLGET: 995 cqp->cq_size = sizeof (int); 996 break; 997 default: 998 cmn_err(CE_WARN, 999 "ttcompat: Unknown ioctl to copyout\n"); 1000 break; 1001 } 1002 cqp->cq_flag = 0; 1003 cqp->cq_private = NULL; 1004 tp->t_state |= TS_W_OUT; 1005 putnext(q, mp); 1006 } 1007 1008 1009 /* 1010 * Called when an M_IOCNAK message is seen on the read queue; if this is 1011 * the response we were waiting for, cancel the wait. Pass the reply up; 1012 * if we were waiting for this response, we can't complete the "ioctl" and 1013 * the NAK will tell that to the guy above us. 1014 * If this wasn't the response we were waiting for, just pass it up. 1015 */ 1016 static void 1017 ttcompat_ioctl_nak(queue_t *q, mblk_t *mp) 1018 { 1019 ttcompat_state_t *tp; 1020 struct iocblk *iocp; 1021 1022 iocp = (struct iocblk *)mp->b_rptr; 1023 tp = (ttcompat_state_t *)q->q_ptr; 1024 1025 if (tp->t_state&TS_IOCWAIT && iocp->ioc_id == tp->t_iocid) { 1026 tp->t_state &= ~TS_IOCWAIT; /* this call isn't going through */ 1027 tp->t_arg = 0; /* we may have stashed the 3rd argument */ 1028 } 1029 putnext(q, mp); 1030 } 1031 1032 #define FROM_COMPAT_CHAR(to, from) { if ((to = from) == 0377) to = 0; } 1033 1034 static void 1035 from_compat(compat_state_t *csp, struct termios *termiosp) 1036 { 1037 termiosp->c_iflag = 0; 1038 termiosp->c_oflag &= (ONLRET|ONOCR); 1039 1040 termiosp->c_cflag = (termiosp->c_cflag & 1041 (CRTSCTS|CRTSXOFF|PAREXT|LOBLK|HUPCL)) | CREAD; 1042 1043 if (csp->t_ospeed > CBAUD) { 1044 termiosp->c_cflag |= ((csp->t_ospeed - CBAUD - 1) & CBAUD) | 1045 CBAUDEXT; 1046 } else { 1047 termiosp->c_cflag |= csp->t_ospeed & CBAUD; 1048 } 1049 1050 if (csp->t_ospeed != csp->t_ispeed) { 1051 if (csp->t_ispeed > (CIBAUD >> IBSHIFT)) { 1052 termiosp->c_cflag |= CIBAUDEXT | 1053 (((csp->t_ispeed - (CIBAUD >> IBSHIFT) - 1) << 1054 IBSHIFT) & CIBAUD); 1055 } else { 1056 termiosp->c_cflag |= (csp->t_ispeed << IBSHIFT) & 1057 CIBAUD; 1058 } 1059 /* hang up if ispeed=0 */ 1060 if (csp->t_ispeed == 0) 1061 termiosp->c_cflag &= ~CBAUD & ~CBAUDEXT; 1062 } 1063 if (csp->t_ispeed == B110 || csp->t_xflags & STOPB) 1064 termiosp->c_cflag |= CSTOPB; 1065 termiosp->c_lflag = ECHOK; 1066 FROM_COMPAT_CHAR(termiosp->c_cc[VERASE], csp->t_erase); 1067 FROM_COMPAT_CHAR(termiosp->c_cc[VKILL], csp->t_kill); 1068 FROM_COMPAT_CHAR(termiosp->c_cc[VINTR], csp->t_intrc); 1069 FROM_COMPAT_CHAR(termiosp->c_cc[VQUIT], csp->t_quitc); 1070 FROM_COMPAT_CHAR(termiosp->c_cc[VSTART], csp->t_startc); 1071 FROM_COMPAT_CHAR(termiosp->c_cc[VSTOP], csp->t_stopc); 1072 termiosp->c_cc[VEOL2] = 0; 1073 FROM_COMPAT_CHAR(termiosp->c_cc[VSUSP], csp->t_suspc); 1074 /* is this useful? */ 1075 FROM_COMPAT_CHAR(termiosp->c_cc[VDSUSP], csp->t_dsuspc); 1076 FROM_COMPAT_CHAR(termiosp->c_cc[VREPRINT], csp->t_rprntc); 1077 FROM_COMPAT_CHAR(termiosp->c_cc[VDISCARD], csp->t_flushc); 1078 FROM_COMPAT_CHAR(termiosp->c_cc[VWERASE], csp->t_werasc); 1079 FROM_COMPAT_CHAR(termiosp->c_cc[VLNEXT], csp->t_lnextc); 1080 termiosp->c_cc[VSTATUS] = 0; 1081 if (csp->t_flags & O_TANDEM) 1082 termiosp->c_iflag |= IXOFF; 1083 if (csp->t_flags & O_LCASE) { 1084 termiosp->c_iflag |= IUCLC; 1085 termiosp->c_oflag |= OLCUC; 1086 termiosp->c_lflag |= XCASE; 1087 } 1088 if (csp->t_flags & O_ECHO) 1089 termiosp->c_lflag |= ECHO; 1090 if (csp->t_flags & O_CRMOD) { 1091 termiosp->c_iflag |= ICRNL; 1092 termiosp->c_oflag |= ONLCR; 1093 switch (csp->t_flags & O_CRDELAY) { 1094 1095 case O_CR1: 1096 termiosp->c_oflag |= CR2; 1097 break; 1098 1099 case O_CR2: 1100 termiosp->c_oflag |= CR3; 1101 break; 1102 } 1103 } else { 1104 if ((csp->t_flags & O_NLDELAY) == O_NL1) 1105 termiosp->c_oflag |= ONLRET|CR1; /* tty37 */ 1106 } 1107 if ((csp->t_flags & O_NLDELAY) == O_NL2) 1108 termiosp->c_oflag |= NL1; 1109 /* 1110 * When going into RAW mode, the special characters controlled by the 1111 * POSIX IEXTEN bit no longer apply; when leaving, they do. 1112 */ 1113 if (csp->t_flags & O_RAW) { 1114 termiosp->c_cflag |= CS8; 1115 termiosp->c_iflag &= ~(ICRNL|IUCLC); 1116 termiosp->c_lflag &= ~(XCASE|IEXTEN); 1117 } else { 1118 termiosp->c_iflag |= IMAXBEL|BRKINT|IGNPAR; 1119 if (termiosp->c_cc[VSTOP] != 0 && termiosp->c_cc[VSTART] != 0) 1120 termiosp->c_iflag |= IXON; 1121 if (csp->t_flags & O_LITOUT) 1122 termiosp->c_cflag |= CS8; 1123 else { 1124 if (csp->t_flags & O_PASS8) 1125 termiosp->c_cflag |= CS8; 1126 /* XXX - what about 8 bits plus parity? */ 1127 else { 1128 switch (csp->t_flags & (O_EVENP|O_ODDP)) { 1129 1130 case 0: 1131 termiosp->c_iflag |= ISTRIP; 1132 termiosp->c_cflag |= CS8; 1133 break; 1134 1135 case O_EVENP: 1136 termiosp->c_iflag |= INPCK|ISTRIP; 1137 termiosp->c_cflag |= CS7|PARENB; 1138 break; 1139 1140 case O_ODDP: 1141 termiosp->c_iflag |= INPCK|ISTRIP; 1142 termiosp->c_cflag |= CS7|PARENB|PARODD; 1143 break; 1144 1145 case O_EVENP|O_ODDP: 1146 termiosp->c_iflag |= ISTRIP; 1147 termiosp->c_cflag |= CS7|PARENB; 1148 break; 1149 } 1150 } 1151 if (!(csp->t_xflags & NOPOST)) 1152 termiosp->c_oflag |= OPOST; 1153 } 1154 termiosp->c_lflag |= IEXTEN; 1155 if (!(csp->t_xflags & NOISIG)) 1156 termiosp->c_lflag |= ISIG; 1157 if (!(csp->t_flags & O_CBREAK)) 1158 termiosp->c_lflag |= ICANON; 1159 if (csp->t_flags & O_CTLECH) 1160 termiosp->c_lflag |= ECHOCTL; 1161 } 1162 switch (csp->t_flags & O_TBDELAY) { 1163 1164 case O_TAB1: 1165 termiosp->c_oflag |= TAB1; 1166 break; 1167 1168 case O_TAB2: 1169 termiosp->c_oflag |= TAB2; 1170 break; 1171 1172 case O_XTABS: 1173 termiosp->c_oflag |= TAB3; 1174 break; 1175 } 1176 if (csp->t_flags & O_VTDELAY) 1177 termiosp->c_oflag |= FFDLY; 1178 if (csp->t_flags & O_BSDELAY) 1179 termiosp->c_oflag |= BSDLY; 1180 if (csp->t_flags & O_PRTERA) 1181 termiosp->c_lflag |= ECHOPRT; 1182 if (csp->t_flags & O_CRTERA) 1183 termiosp->c_lflag |= ECHOE; 1184 if (csp->t_flags & O_TOSTOP) 1185 termiosp->c_lflag |= TOSTOP; 1186 if (csp->t_flags & O_FLUSHO) 1187 termiosp->c_lflag |= FLUSHO; 1188 if (csp->t_flags & O_NOHANG) 1189 termiosp->c_cflag |= CLOCAL; 1190 if (csp->t_flags & O_CRTKIL) 1191 termiosp->c_lflag |= ECHOKE; 1192 if (csp->t_flags & O_PENDIN) 1193 termiosp->c_lflag |= PENDIN; 1194 if (!(csp->t_flags & O_DECCTQ)) 1195 termiosp->c_iflag |= IXANY; 1196 if (csp->t_flags & O_NOFLSH) 1197 termiosp->c_lflag |= NOFLSH; 1198 if (termiosp->c_lflag & ICANON) { 1199 FROM_COMPAT_CHAR(termiosp->c_cc[VEOF], csp->t_eofc); 1200 FROM_COMPAT_CHAR(termiosp->c_cc[VEOL], csp->t_brkc); 1201 } else { 1202 termiosp->c_cc[VMIN] = 1; 1203 termiosp->c_cc[VTIME] = 0; 1204 } 1205 } 1206 1207 #define TO_COMPAT_CHAR(to, from) { if ((to = from) == 0) to = (uchar_t)0377; } 1208 1209 static void 1210 to_compat(struct termios *termiosp, compat_state_t *csp) 1211 { 1212 csp->t_xflags &= (NOISIG|NOPOST); 1213 csp->t_ospeed = termiosp->c_cflag & CBAUD; 1214 csp->t_ispeed = (termiosp->c_cflag & CIBAUD) >> IBSHIFT; 1215 if (sgttyb_handling > 0) { 1216 if (termiosp->c_cflag & CBAUDEXT) 1217 csp->t_ospeed += CBAUD + 1; 1218 if (termiosp->c_cflag & CIBAUDEXT) 1219 csp->t_ispeed += (CIBAUD >> IBSHIFT) + 1; 1220 } 1221 if (csp->t_ispeed == 0) 1222 csp->t_ispeed = csp->t_ospeed; 1223 if ((termiosp->c_cflag & CSTOPB) && csp->t_ispeed != B110) 1224 csp->t_xflags |= STOPB; 1225 TO_COMPAT_CHAR(csp->t_erase, termiosp->c_cc[VERASE]); 1226 TO_COMPAT_CHAR(csp->t_kill, termiosp->c_cc[VKILL]); 1227 TO_COMPAT_CHAR(csp->t_intrc, termiosp->c_cc[VINTR]); 1228 TO_COMPAT_CHAR(csp->t_quitc, termiosp->c_cc[VQUIT]); 1229 TO_COMPAT_CHAR(csp->t_startc, termiosp->c_cc[VSTART]); 1230 TO_COMPAT_CHAR(csp->t_stopc, termiosp->c_cc[VSTOP]); 1231 TO_COMPAT_CHAR(csp->t_suspc, termiosp->c_cc[VSUSP]); 1232 TO_COMPAT_CHAR(csp->t_dsuspc, termiosp->c_cc[VDSUSP]); 1233 TO_COMPAT_CHAR(csp->t_rprntc, termiosp->c_cc[VREPRINT]); 1234 TO_COMPAT_CHAR(csp->t_flushc, termiosp->c_cc[VDISCARD]); 1235 TO_COMPAT_CHAR(csp->t_werasc, termiosp->c_cc[VWERASE]); 1236 TO_COMPAT_CHAR(csp->t_lnextc, termiosp->c_cc[VLNEXT]); 1237 csp->t_flags &= (O_CTLECH|O_LITOUT|O_PASS8|O_ODDP|O_EVENP); 1238 if (termiosp->c_iflag & IXOFF) 1239 csp->t_flags |= O_TANDEM; 1240 if (!(termiosp->c_iflag & 1241 (IMAXBEL|BRKINT|IGNPAR|PARMRK|INPCK|ISTRIP| 1242 INLCR|IGNCR|ICRNL|IUCLC|IXON)) && 1243 !(termiosp->c_oflag & OPOST) && 1244 (termiosp->c_cflag & (CSIZE|PARENB)) == CS8 && 1245 !(termiosp->c_lflag & (ISIG|ICANON|XCASE|IEXTEN))) 1246 csp->t_flags |= O_RAW; 1247 else { 1248 if (!(termiosp->c_iflag & IXON)) { 1249 csp->t_startc = (uchar_t)0377; 1250 csp->t_stopc = (uchar_t)0377; 1251 } 1252 if ((termiosp->c_cflag & (CSIZE|PARENB)) == CS8 && 1253 !(termiosp->c_oflag & OPOST)) 1254 csp->t_flags |= O_LITOUT; 1255 else { 1256 csp->t_flags &= ~O_LITOUT; 1257 if ((termiosp->c_cflag & (CSIZE|PARENB)) == CS8) { 1258 if (!(termiosp->c_iflag & ISTRIP)) 1259 csp->t_flags |= O_PASS8; 1260 } else { 1261 csp->t_flags &= ~(O_ODDP|O_EVENP|O_PASS8); 1262 if (termiosp->c_cflag & PARODD) 1263 csp->t_flags |= O_ODDP; 1264 else if (termiosp->c_iflag & INPCK) 1265 csp->t_flags |= O_EVENP; 1266 else 1267 csp->t_flags |= O_ODDP|O_EVENP; 1268 } 1269 if (!(termiosp->c_oflag & OPOST)) 1270 csp->t_xflags |= NOPOST; 1271 else 1272 csp->t_xflags &= ~NOPOST; 1273 } 1274 if (!(termiosp->c_lflag & ISIG)) 1275 csp->t_xflags |= NOISIG; 1276 else 1277 csp->t_xflags &= ~NOISIG; 1278 if (!(termiosp->c_lflag & ICANON)) 1279 csp->t_flags |= O_CBREAK; 1280 if (termiosp->c_lflag & ECHOCTL) 1281 csp->t_flags |= O_CTLECH; 1282 else 1283 csp->t_flags &= ~O_CTLECH; 1284 } 1285 if (termiosp->c_oflag & OLCUC) 1286 csp->t_flags |= O_LCASE; 1287 if (termiosp->c_lflag&ECHO) 1288 csp->t_flags |= O_ECHO; 1289 if (termiosp->c_oflag & ONLCR) { 1290 csp->t_flags |= O_CRMOD; 1291 switch (termiosp->c_oflag & CRDLY) { 1292 1293 case CR2: 1294 csp->t_flags |= O_CR1; 1295 break; 1296 1297 case CR3: 1298 csp->t_flags |= O_CR2; 1299 break; 1300 } 1301 } else { 1302 if ((termiosp->c_oflag & CR1) && 1303 (termiosp->c_oflag & ONLRET)) 1304 csp->t_flags |= O_NL1; /* tty37 */ 1305 } 1306 if ((termiosp->c_oflag & ONLRET) && (termiosp->c_oflag & NL1)) 1307 csp->t_flags |= O_NL2; 1308 switch (termiosp->c_oflag & TABDLY) { 1309 1310 case TAB1: 1311 csp->t_flags |= O_TAB1; 1312 break; 1313 1314 case TAB2: 1315 csp->t_flags |= O_TAB2; 1316 break; 1317 1318 case XTABS: 1319 csp->t_flags |= O_XTABS; 1320 break; 1321 } 1322 if (termiosp->c_oflag & FFDLY) 1323 csp->t_flags |= O_VTDELAY; 1324 if (termiosp->c_oflag & BSDLY) 1325 csp->t_flags |= O_BSDELAY; 1326 if (termiosp->c_lflag & ECHOPRT) 1327 csp->t_flags |= O_PRTERA; 1328 if (termiosp->c_lflag & ECHOE) 1329 csp->t_flags |= (O_CRTERA|O_CRTBS); 1330 if (termiosp->c_lflag & TOSTOP) 1331 csp->t_flags |= O_TOSTOP; 1332 if (termiosp->c_lflag & FLUSHO) 1333 csp->t_flags |= O_FLUSHO; 1334 if (termiosp->c_cflag & CLOCAL) 1335 csp->t_flags |= O_NOHANG; 1336 if (termiosp->c_lflag & ECHOKE) 1337 csp->t_flags |= O_CRTKIL; 1338 if (termiosp->c_lflag & PENDIN) 1339 csp->t_flags |= O_PENDIN; 1340 if (!(termiosp->c_iflag & IXANY)) 1341 csp->t_flags |= O_DECCTQ; 1342 if (termiosp->c_lflag & NOFLSH) 1343 csp->t_flags |= O_NOFLSH; 1344 if (termiosp->c_lflag & ICANON) { 1345 TO_COMPAT_CHAR(csp->t_eofc, termiosp->c_cc[VEOF]); 1346 TO_COMPAT_CHAR(csp->t_brkc, termiosp->c_cc[VEOL]); 1347 } else { 1348 termiosp->c_cc[VMIN] = 1; 1349 termiosp->c_cc[VTIME] = 0; 1350 } 1351 } 1352