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