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