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.
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.
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]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
31 * University Copyright- Copyright (c) 1982, 1986, 1988
32 * The Regents of the University of California
35 * University Acknowledgment- Portions of this document are derived from
36 * software developed by the University of California, Berkeley, and its
41 * Module to intercept old V7 and 4BSD "ioctl" calls.
44 #include <sys/types.h>
45 #include <sys/param.h>
46 #include <sys/signal.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>
59 #include <sys/sunddi.h>
61 #include <sys/policy.h>
64 * This is the loadable module wrapper.
67 #include <sys/modctl.h>
69 /* See os/streamio.c */
70 extern int sgttyb_handling
;
72 static struct streamtab ttcoinfo
;
74 static struct fmodsw fsw
= {
77 D_MTQPAIR
| D_MP
| _D_SINGLE_INSTANCE
81 * Module linkage information for the kernel.
84 static struct modlstrmod modlstrmod
= {
90 static struct modlinkage modlinkage
= {
91 MODREV_1
, &modlstrmod
, NULL
97 return (mod_install(&modlinkage
));
103 return (mod_remove(&modlinkage
));
107 _info(struct modinfo
*modinfop
)
109 return (mod_info(&modlinkage
, modinfop
));
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
*);
117 static struct module_info ttycompatmiinfo
= {
126 static struct qinit ttycompatrinit
= {
127 (int (*)())ttcompatrput
,
135 static struct module_info ttycompatmoinfo
= {
144 static struct qinit ttycompatwinit
= {
145 (int (*)())ttcompatwput
,
153 static struct streamtab ttcoinfo
= {
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
*);
168 * Open - get the current modes and translate them to the V7/4BSD equivalent.
172 ttcompatopen(queue_t
*q
, dev_t
*devp
, int oflag
, int sflag
, cred_t
*crp
)
174 ttcompat_state_t
*tp
;
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) {
183 return (0); /* already attached */
185 tp
= kmem_zalloc(sizeof (ttcompat_state_t
), KM_SLEEP
);
195 ttcompatclose(queue_t
*q
, int flag
, cred_t
*crp
)
197 ttcompat_state_t
*tp
= (ttcompat_state_t
*)q
->q_ptr
;
200 /* Dump the state structure, then unlink it */
202 if (tp
->t_bufcallid
!= 0) {
203 qunbufcall(q
, tp
->t_bufcallid
);
206 if ((mp
= tp
->t_iocpending
) != NULL
)
208 kmem_free(tp
, sizeof (ttcompat_state_t
));
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.
221 ttcompatrput(queue_t
*q
, mblk_t
*mp
)
223 switch (mp
->b_datap
->db_type
) {
226 ttcompat_ioctl_ack(q
, mp
);
230 ttcompat_ioctl_nak(q
, mp
);
240 * Line discipline output queue put procedure: speeds M_IOCTL
244 ttcompatwput(queue_t
*q
, mblk_t
*mp
)
246 ttcompat_state_t
*tp
;
248 struct copyresp
*csp
;
249 struct iocblk
*iocbp
;
251 tp
= (ttcompat_state_t
*)q
->q_ptr
;
254 * Process some M_IOCTL messages here; pass everything else down.
256 switch (mp
->b_datap
->db_type
) {
263 iocbp
= (struct iocblk
*)mp
->b_rptr
;
265 switch (iocbp
->ioc_cmd
) {
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
);
279 if (iocbp
->ioc_count
!= TRANSPARENT
) {
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
) {
289 cqp
->cq_size
= sizeof (struct sgttyb
);
292 cqp
->cq_size
= sizeof (struct ltchars
);
295 cqp
->cq_size
= sizeof (struct tchars
);
301 cqp
->cq_size
= sizeof (int);
307 cqp
->cq_private
= 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
;
316 } /* switch ioc_cmd */
318 csp
= (struct copyresp
*)mp
->b_rptr
;
320 switch (csp
->cp_cmd
) {
333 tp
->t_state
&= ~TS_W_IN
;
334 if (csp
->cp_rval
!= 0) { /* failure */
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;
346 ttcompat_do_ioctl(tp
, q
, mp
);
352 tp
->t_state
&= ~TS_W_OUT
;
353 if (csp
->cp_rval
!= 0) { /* failure */
358 iocbp
= (struct iocblk
*)mp
->b_rptr
;
359 iocbp
->ioc_count
= 0;
360 iocbp
->ioc_error
= 0;
362 mp
->b_datap
->db_type
= M_IOCACK
;
366 } /* switch cp_cmd */
367 } /* end message switch */
371 * Retry an "ioctl", now that "bufcall" claims we may be able to allocate
372 * the buffer we need.
375 ttcompat_reioctl(void *arg
)
378 ttcompat_state_t
*tp
;
381 tp
= (ttcompat_state_t
*)q
->q_ptr
;
384 if ((mp
= tp
->t_iocpending
) != NULL
) {
385 tp
->t_iocpending
= NULL
; /* not pending any more */
386 ttcompat_do_ioctl(tp
, q
, mp
);
391 * Handle old-style "ioctl" messages; pass the rest down unmolested.
394 ttcompat_do_ioctl(ttcompat_state_t
*tp
, queue_t
*q
, mblk_t
*mp
)
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.
406 iocp
= (struct iocblk
*)mp
->b_rptr
;
407 switch (iocp
->ioc_cmd
) {
410 * "get"-style calls that get translated data from the "termios"
411 * structure. Save the existing code and pass it down as a TCGETS.
416 if (iocp
->ioc_count
!= TRANSPARENT
) {
417 miocnak(q
, mp
, 0, EINVAL
);
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
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 */
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.
452 error
= miocpullup(mp
, sizeof (struct sgttyb
));
454 miocnak(q
, mp
, 0, error
);
457 tp
->t_new_sgttyb
= *((struct sgttyb
*)mp
->b_cont
->b_rptr
);
461 error
= miocpullup(mp
, sizeof (struct tchars
));
463 miocnak(q
, mp
, 0, error
);
466 tp
->t_new_tchars
= *((struct tchars
*)mp
->b_cont
->b_rptr
);
470 error
= miocpullup(mp
, sizeof (struct ltchars
));
472 miocnak(q
, mp
, 0, error
);
475 tp
->t_new_ltchars
= *((struct ltchars
*)mp
->b_cont
->b_rptr
);
481 error
= miocpullup(mp
, sizeof (int));
483 miocnak(q
, mp
, 0, error
);
486 tp
->t_new_lflags
= *(int *)mp
->b_cont
->b_rptr
;
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.
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 */
506 * "set"-style call that sets DTR. Pretend that it was a TIOCMBIS
507 * with TIOCM_DTR set.
512 if ((datap
= allocb(sizeof (int), BPRI_HI
)) == NULL
)
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
)
519 mp
->b_cont
= datap
; /* attach the data */
520 iocp
->ioc_count
= sizeof (int); /* in case driver checks */
525 * "set"-style call that clears DTR. Pretend that it was a TIOCMBIC
526 * with TIOCM_DTR set.
531 if ((datap
= allocb(sizeof (int), BPRI_HI
)) == NULL
)
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
)
538 mp
->b_cont
= datap
; /* attach the data */
539 iocp
->ioc_count
= sizeof (int); /* in case driver checks */
544 * Translate into the S5 form of TCFLSH.
549 error
= miocpullup(mp
, sizeof (int));
551 miocnak(q
, mp
, 0, error
);
554 flags
= *(int *)mp
->b_cont
->b_rptr
;
556 switch (flags
&(FREAD
|FWRITE
)) {
560 flags
= 2; /* flush 'em both */
564 flags
= 0; /* flush read */
568 flags
= 1; /* flush write */
571 iocp
->ioc_cmd
= TCFLSH
; /* turn it into a TCFLSH */
572 *(int *)mp
->b_cont
->b_rptr
= flags
; /* fiddle the arg */
577 * Turn into a TCXONC.
582 if ((datap
= allocb(sizeof (int), BPRI_HI
)) == NULL
)
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
)
590 mp
->b_cont
= datap
; /* attach the data */
597 if ((datap
= allocb(sizeof (int), BPRI_HI
)) == NULL
)
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
)
605 mp
->b_cont
= datap
; /* attach the data */
618 * All of these ioctls are just ACK'd, except for
619 * TIOCSETD, which must be for line discipline zero.
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
;
634 mp
->b_datap
->db_type
= M_IOCACK
;
637 iocp
->ioc_rval
= TIOC
;
641 /* check for binary value of XCLUDE flag ???? */
642 tp
->t_new_lflags
|= XCLUDE
;
643 mp
->b_datap
->db_type
= M_IOCACK
;
650 tp
->t_new_lflags
&= ~XCLUDE
;
651 mp
->b_datap
->db_type
= M_IOCACK
;
660 * We don't reply to most calls, we just pass them down,
661 * possibly after modifying the arguments.
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.
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
);
680 tp
->t_bufcallid
= qbufcall(q
, sizeof (struct iocblk
), BPRI_HI
,
681 ttcompat_reioctl
, q
);
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)
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.
700 ttcompat_ioctl_ack(queue_t
*q
, mblk_t
*mp
)
702 ttcompat_state_t
*tp
;
706 tp
= (ttcompat_state_t
*)q
->q_ptr
;
707 iocp
= (struct iocblk
*)mp
->b_rptr
;
709 if (!(tp
->t_state
&TS_IOCWAIT
) || iocp
->ioc_id
!= tp
->t_iocid
) {
711 * This isn't the reply we're looking for. Move along.
717 datap
= mp
->b_cont
; /* mblk containing data going up */
719 switch (tp
->t_ioccmd
) {
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
;
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).
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
);
747 /* you are lucky - stream head knows how to copy you out */
749 tp
->t_state
&= ~TS_IOCWAIT
; /* we got what we wanted */
751 iocp
->ioc_cmd
= tp
->t_ioccmd
;
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
);
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
);
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);
786 * Get the current state from the GETS data, and
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
;
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.
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);
818 * Replace the data that came up with the updated data.
820 from_compat(&tp
->t_curstate
, (struct termios
*)datap
->b_rptr
);
823 * Send it back down as a TCSETS or TCSETSF.
825 iocp
->ioc_cmd
= (tp
->t_ioccmd
== TIOCSETP
) ? TCSETSF
: TCSETS
;
830 * Get the current state from the GETS data, and
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
));
838 * Replace the data that came up with the updated data.
840 from_compat(&tp
->t_curstate
, (struct termios
*)datap
->b_rptr
);
843 * Send it back down as a TCSETS.
845 iocp
->ioc_cmd
= TCSETS
;
850 * Get the current state from the GETS data, and
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
));
858 * Replace the data that came up with the updated data.
860 from_compat(&tp
->t_curstate
, (struct termios
*)datap
->b_rptr
);
863 * Send it back down as a TCSETS.
865 iocp
->ioc_cmd
= TCSETS
;
870 * Get the current state from the GETS data, and
873 to_compat((struct termios
*)datap
->b_rptr
, &tp
->t_curstate
);
874 tp
->t_curstate
.t_flags
|= (tp
->t_new_lflags
<< 16);
877 * Replace the data that came up with the updated data.
879 from_compat(&tp
->t_curstate
, (struct termios
*)datap
->b_rptr
);
882 * Send it back down as a TCSETS.
884 iocp
->ioc_cmd
= TCSETS
;
889 * Get the current state from the GETS data, and
892 to_compat((struct termios
*)datap
->b_rptr
, &tp
->t_curstate
);
893 tp
->t_curstate
.t_flags
&= ~(tp
->t_new_lflags
<< 16);
896 * Replace the data that came up with the updated data.
898 from_compat(&tp
->t_curstate
, (struct termios
*)datap
->b_rptr
);
901 * Send it back down as a TCSETS.
903 iocp
->ioc_cmd
= TCSETS
;
908 * Get the current state from the GETS data, and
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);
916 * Replace the data that came up with the updated data.
918 from_compat(&tp
->t_curstate
, (struct termios
*)datap
->b_rptr
);
921 * Send it back down as a TCSETS.
923 iocp
->ioc_cmd
= TCSETS
;
928 * Replace the data that came up with the updated data.
930 ((struct termios
*)datap
->b_rptr
)->c_cflag
|= HUPCL
;
933 * Send it back down as a TCSETS.
935 iocp
->ioc_cmd
= TCSETS
;
940 * We're acknowledging the terminal reset ioctl that we sent
941 * when the module was opened.
943 tp
->t_state
&= ~(TS_IOCWAIT
| TS_TIOCNAK
);
948 cmn_err(CE_WARN
, "ttcompat: Unexpected ioctl acknowledgment\n");
952 * All the calls that return something return 0.
954 tp
->t_state
&= ~TS_IOCWAIT
; /* we got what we wanted */
957 /* copy out the data - ioctl transparency */
958 iocp
->ioc_cmd
= tp
->t_ioccmd
;
964 * Send a "get state" reply back down, with suitably-modified
965 * state, as a "set state" "ioctl".
967 tp
->t_state
&= ~TS_IOCWAIT
;
968 mp
->b_datap
->db_type
= M_IOCTL
;
969 mp
->b_wptr
= mp
->b_rptr
+ sizeof (struct iocblk
);
972 /* Called from ttcompatrput M_IOCACK processing. */
973 /* Copies out the data using M_COPYOUT messages */
976 ttcopyout(queue_t
*q
, mblk_t
*mp
)
979 ttcompat_state_t
*tp
;
981 tp
= (ttcompat_state_t
*)q
->q_ptr
;
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
) {
989 cqp
->cq_size
= sizeof (struct ltchars
);
992 cqp
->cq_size
= sizeof (struct tchars
);
995 cqp
->cq_size
= sizeof (int);
999 "ttcompat: Unknown ioctl to copyout\n");
1003 cqp
->cq_private
= NULL
;
1004 tp
->t_state
|= TS_W_OUT
;
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.
1017 ttcompat_ioctl_nak(queue_t
*q
, mblk_t
*mp
)
1019 ttcompat_state_t
*tp
;
1020 struct iocblk
*iocp
;
1022 iocp
= (struct iocblk
*)mp
->b_rptr
;
1023 tp
= (ttcompat_state_t
*)q
->q_ptr
;
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 */
1032 #define FROM_COMPAT_CHAR(to, from) { if ((to = from) == 0377) to = 0; }
1035 from_compat(compat_state_t
*csp
, struct termios
*termiosp
)
1037 termiosp
->c_iflag
= 0;
1038 termiosp
->c_oflag
&= (ONLRET
|ONOCR
);
1040 termiosp
->c_cflag
= (termiosp
->c_cflag
&
1041 (CRTSCTS
|CRTSXOFF
|PAREXT
|LOBLK
|HUPCL
)) | CREAD
;
1043 if (csp
->t_ospeed
> CBAUD
) {
1044 termiosp
->c_cflag
|= ((csp
->t_ospeed
- CBAUD
- 1) & CBAUD
) |
1047 termiosp
->c_cflag
|= csp
->t_ospeed
& CBAUD
;
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) <<
1056 termiosp
->c_cflag
|= (csp
->t_ispeed
<< IBSHIFT
) &
1059 /* hang up if ispeed=0 */
1060 if (csp
->t_ispeed
== 0)
1061 termiosp
->c_cflag
&= ~CBAUD
& ~CBAUDEXT
;
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
;
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
) {
1096 termiosp
->c_oflag
|= CR2
;
1100 termiosp
->c_oflag
|= CR3
;
1104 if ((csp
->t_flags
& O_NLDELAY
) == O_NL1
)
1105 termiosp
->c_oflag
|= ONLRET
|CR1
; /* tty37 */
1107 if ((csp
->t_flags
& O_NLDELAY
) == O_NL2
)
1108 termiosp
->c_oflag
|= NL1
;
1110 * When going into RAW mode, the special characters controlled by the
1111 * POSIX IEXTEN bit no longer apply; when leaving, they do.
1113 if (csp
->t_flags
& O_RAW
) {
1114 termiosp
->c_cflag
|= CS8
;
1115 termiosp
->c_iflag
&= ~(ICRNL
|IUCLC
);
1116 termiosp
->c_lflag
&= ~(XCASE
|IEXTEN
);
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
;
1124 if (csp
->t_flags
& O_PASS8
)
1125 termiosp
->c_cflag
|= CS8
;
1126 /* XXX - what about 8 bits plus parity? */
1128 switch (csp
->t_flags
& (O_EVENP
|O_ODDP
)) {
1131 termiosp
->c_iflag
|= ISTRIP
;
1132 termiosp
->c_cflag
|= CS8
;
1136 termiosp
->c_iflag
|= INPCK
|ISTRIP
;
1137 termiosp
->c_cflag
|= CS7
|PARENB
;
1141 termiosp
->c_iflag
|= INPCK
|ISTRIP
;
1142 termiosp
->c_cflag
|= CS7
|PARENB
|PARODD
;
1145 case O_EVENP
|O_ODDP
:
1146 termiosp
->c_iflag
|= ISTRIP
;
1147 termiosp
->c_cflag
|= CS7
|PARENB
;
1151 if (!(csp
->t_xflags
& NOPOST
))
1152 termiosp
->c_oflag
|= OPOST
;
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
;
1162 switch (csp
->t_flags
& O_TBDELAY
) {
1165 termiosp
->c_oflag
|= TAB1
;
1169 termiosp
->c_oflag
|= TAB2
;
1173 termiosp
->c_oflag
|= TAB3
;
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
);
1202 termiosp
->c_cc
[VMIN
] = 1;
1203 termiosp
->c_cc
[VTIME
] = 0;
1207 #define TO_COMPAT_CHAR(to, from) { if ((to = from) == 0) to = (uchar_t)0377; }
1210 to_compat(struct termios
*termiosp
, compat_state_t
*csp
)
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;
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
;
1248 if (!(termiosp
->c_iflag
& IXON
)) {
1249 csp
->t_startc
= (uchar_t
)0377;
1250 csp
->t_stopc
= (uchar_t
)0377;
1252 if ((termiosp
->c_cflag
& (CSIZE
|PARENB
)) == CS8
&&
1253 !(termiosp
->c_oflag
& OPOST
))
1254 csp
->t_flags
|= O_LITOUT
;
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
;
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
;
1267 csp
->t_flags
|= O_ODDP
|O_EVENP
;
1269 if (!(termiosp
->c_oflag
& OPOST
))
1270 csp
->t_xflags
|= NOPOST
;
1272 csp
->t_xflags
&= ~NOPOST
;
1274 if (!(termiosp
->c_lflag
& ISIG
))
1275 csp
->t_xflags
|= NOISIG
;
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
;
1283 csp
->t_flags
&= ~O_CTLECH
;
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
) {
1294 csp
->t_flags
|= O_CR1
;
1298 csp
->t_flags
|= O_CR2
;
1302 if ((termiosp
->c_oflag
& CR1
) &&
1303 (termiosp
->c_oflag
& ONLRET
))
1304 csp
->t_flags
|= O_NL1
; /* tty37 */
1306 if ((termiosp
->c_oflag
& ONLRET
) && (termiosp
->c_oflag
& NL1
))
1307 csp
->t_flags
|= O_NL2
;
1308 switch (termiosp
->c_oflag
& TABDLY
) {
1311 csp
->t_flags
|= O_TAB1
;
1315 csp
->t_flags
|= O_TAB2
;
1319 csp
->t_flags
|= O_XTABS
;
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
]);
1348 termiosp
->c_cc
[VMIN
] = 1;
1349 termiosp
->c_cc
[VTIME
] = 0;