1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/termios_internal.h>
3 
4 /*
5  * c_cc characters in the termio structure.  Oh, how I love being
6  * backwardly compatible.  Notice that character 4 and 5 are
7  * interpreted differently depending on whether ICANON is set in
8  * c_lflag.  If it's set, they are used as _VEOF and _VEOL, otherwise
9  * as _VMIN and V_TIME.  This is for compatibility with OSF/1 (which
10  * is compatible with sysV)...
11  */
12 #define _VMIN	4
13 #define _VTIME	5
14 
kernel_termios_to_user_termio(struct termio __user * termio,struct ktermios * termios)15 int kernel_termios_to_user_termio(struct termio __user *termio,
16 						struct ktermios *termios)
17 {
18 	struct termio v;
19 	memset(&v, 0, sizeof(struct termio));
20 	v.c_iflag = termios->c_iflag;
21 	v.c_oflag = termios->c_oflag;
22 	v.c_cflag = termios->c_cflag;
23 	v.c_lflag = termios->c_lflag;
24 	v.c_line = termios->c_line;
25 	memcpy(v.c_cc, termios->c_cc, NCC);
26 	if (!(v.c_lflag & ICANON)) {
27 		v.c_cc[_VMIN] = termios->c_cc[VMIN];
28 		v.c_cc[_VTIME] = termios->c_cc[VTIME];
29 	}
30 	return copy_to_user(termio, &v, sizeof(struct termio));
31 }
32 
user_termios_to_kernel_termios(struct ktermios * k,struct termios2 __user * u)33 int user_termios_to_kernel_termios(struct ktermios *k,
34 						 struct termios2 __user *u)
35 {
36 	int err;
37 	err  = get_user(k->c_iflag, &u->c_iflag);
38 	err |= get_user(k->c_oflag, &u->c_oflag);
39 	err |= get_user(k->c_cflag, &u->c_cflag);
40 	err |= get_user(k->c_lflag, &u->c_lflag);
41 	err |= get_user(k->c_line,  &u->c_line);
42 	err |= copy_from_user(k->c_cc, u->c_cc, NCCS);
43 	if (k->c_lflag & ICANON) {
44 		err |= get_user(k->c_cc[VEOF], &u->c_cc[VEOF]);
45 		err |= get_user(k->c_cc[VEOL], &u->c_cc[VEOL]);
46 	} else {
47 		err |= get_user(k->c_cc[VMIN],  &u->c_cc[_VMIN]);
48 		err |= get_user(k->c_cc[VTIME], &u->c_cc[_VTIME]);
49 	}
50 	err |= get_user(k->c_ispeed,  &u->c_ispeed);
51 	err |= get_user(k->c_ospeed,  &u->c_ospeed);
52 	return err;
53 }
54 
kernel_termios_to_user_termios(struct termios2 __user * u,struct ktermios * k)55 int kernel_termios_to_user_termios(struct termios2 __user *u,
56 						 struct ktermios *k)
57 {
58 	int err;
59 	err  = put_user(k->c_iflag, &u->c_iflag);
60 	err |= put_user(k->c_oflag, &u->c_oflag);
61 	err |= put_user(k->c_cflag, &u->c_cflag);
62 	err |= put_user(k->c_lflag, &u->c_lflag);
63 	err |= put_user(k->c_line, &u->c_line);
64 	err |= copy_to_user(u->c_cc, k->c_cc, NCCS);
65 	if (!(k->c_lflag & ICANON)) {
66 		err |= put_user(k->c_cc[VMIN],  &u->c_cc[_VMIN]);
67 		err |= put_user(k->c_cc[VTIME], &u->c_cc[_VTIME]);
68 	} else {
69 		err |= put_user(k->c_cc[VEOF], &u->c_cc[VEOF]);
70 		err |= put_user(k->c_cc[VEOL], &u->c_cc[VEOL]);
71 	}
72 	err |= put_user(k->c_ispeed, &u->c_ispeed);
73 	err |= put_user(k->c_ospeed, &u->c_ospeed);
74 	return err;
75 }
76 
user_termios_to_kernel_termios_1(struct ktermios * k,struct termios __user * u)77 int user_termios_to_kernel_termios_1(struct ktermios *k,
78 						 struct termios __user *u)
79 {
80 	int err;
81 	err  = get_user(k->c_iflag, &u->c_iflag);
82 	err |= get_user(k->c_oflag, &u->c_oflag);
83 	err |= get_user(k->c_cflag, &u->c_cflag);
84 	err |= get_user(k->c_lflag, &u->c_lflag);
85 	err |= get_user(k->c_line,  &u->c_line);
86 	err |= copy_from_user(k->c_cc, u->c_cc, NCCS);
87 	if (k->c_lflag & ICANON) {
88 		err |= get_user(k->c_cc[VEOF], &u->c_cc[VEOF]);
89 		err |= get_user(k->c_cc[VEOL], &u->c_cc[VEOL]);
90 	} else {
91 		err |= get_user(k->c_cc[VMIN],  &u->c_cc[_VMIN]);
92 		err |= get_user(k->c_cc[VTIME], &u->c_cc[_VTIME]);
93 	}
94 	return err;
95 }
96 
kernel_termios_to_user_termios_1(struct termios __user * u,struct ktermios * k)97 int kernel_termios_to_user_termios_1(struct termios __user *u,
98 						 struct ktermios *k)
99 {
100 	int err;
101 	err  = put_user(k->c_iflag, &u->c_iflag);
102 	err |= put_user(k->c_oflag, &u->c_oflag);
103 	err |= put_user(k->c_cflag, &u->c_cflag);
104 	err |= put_user(k->c_lflag, &u->c_lflag);
105 	err |= put_user(k->c_line, &u->c_line);
106 	err |= copy_to_user(u->c_cc, k->c_cc, NCCS);
107 	if (!(k->c_lflag & ICANON)) {
108 		err |= put_user(k->c_cc[VMIN],  &u->c_cc[_VMIN]);
109 		err |= put_user(k->c_cc[VTIME], &u->c_cc[_VTIME]);
110 	} else {
111 		err |= put_user(k->c_cc[VEOF], &u->c_cc[VEOF]);
112 		err |= put_user(k->c_cc[VEOL], &u->c_cc[VEOL]);
113 	}
114 	return err;
115 }
116