xref: /netbsd-src/sys/compat/linux/common/linux_ioctl.c (revision 9573504567626934c7ee01c7dce0c4bb1dfe7403)
1 /*	$NetBSD: linux_ioctl.c,v 1.9 1995/11/16 18:42:05 thorpej Exp $	*/
2 
3 /*
4  * Copyright (c) 1995 Frank van der Linden
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *      This product includes software developed for the NetBSD Project
18  *      by Frank van der Linden
19  * 4. The name of the author may not be used to endorse or promote products
20  *    derived from this software without specific prior written permission
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include <sys/param.h>
35 #include <sys/proc.h>
36 #include <sys/systm.h>
37 #include <sys/file.h>
38 #include <sys/filedesc.h>
39 #include <sys/ioctl.h>
40 #include <sys/termios.h>
41 #include <sys/tty.h>
42 #include <sys/socket.h>
43 #include <sys/ioctl.h>
44 #include <sys/mount.h>
45 #include <net/if.h>
46 #include <sys/sockio.h>
47 
48 #include <sys/syscallargs.h>
49 
50 #include <compat/linux/linux_types.h>
51 #include <compat/linux/linux_ioctl.h>
52 #include <compat/linux/linux_sockio.h>
53 #include <compat/linux/linux_util.h>
54 #include <compat/linux/linux_signal.h>
55 #include <compat/linux/linux_syscallargs.h>
56 
57 static speed_t linux_speeds[] = {
58 	0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
59 	9600, 19200, 38400, 57600, 115200
60 };
61 
62 static int linux_spmasks[] = {
63 	LINUX_B0, LINUX_B50, LINUX_B75, LINUX_B110, LINUX_B134, LINUX_B150,
64 	LINUX_B200, LINUX_B300, LINUX_B600, LINUX_B1200, LINUX_B1800,
65 	LINUX_B2400, LINUX_B4800, LINUX_B9600, LINUX_B19200, LINUX_B38400,
66 	LINUX_B57600, LINUX_B115200, LINUX_B230400
67 };
68 
69 /*
70  * Deal with termio ioctl cruft. This doesn't look very good..
71  * XXX too much code duplication, obviously..
72  *
73  * The conversion routines between Linux and BSD structures assume
74  * that the fields are already filled with the current values,
75  * so that fields present in BSD but not in Linux keep their current
76  * values.
77  */
78 
79 static int
80 linux_termio_to_bsd_termios(lt, bts)
81 	register struct linux_termio *lt;
82 	register struct termios *bts;
83 {
84 	int index;
85 
86 	bts->c_iflag = 0;
87 	bts->c_iflag |= cvtto_bsd_mask(lt->c_iflag, LINUX_IGNBRK, IGNBRK);
88 	bts->c_iflag |= cvtto_bsd_mask(lt->c_iflag, LINUX_BRKINT, BRKINT);
89 	bts->c_iflag |= cvtto_bsd_mask(lt->c_iflag, LINUX_IGNPAR, IGNPAR);
90 	bts->c_iflag |= cvtto_bsd_mask(lt->c_iflag, LINUX_INPCK, INPCK);
91 	bts->c_iflag |= cvtto_bsd_mask(lt->c_iflag, LINUX_ISTRIP, ISTRIP);
92 	bts->c_iflag |= cvtto_bsd_mask(lt->c_iflag, LINUX_INLCR, INLCR);
93 	bts->c_iflag |= cvtto_bsd_mask(lt->c_iflag, LINUX_IGNCR, IGNCR);
94 	bts->c_iflag |= cvtto_bsd_mask(lt->c_iflag, LINUX_ICRNL, ICRNL);
95 	bts->c_iflag |= cvtto_bsd_mask(lt->c_iflag, LINUX_IXON, IXON);
96 	bts->c_iflag |= cvtto_bsd_mask(lt->c_iflag, LINUX_IXANY, IXANY);
97 	bts->c_iflag |= cvtto_bsd_mask(lt->c_iflag, LINUX_IXOFF, IXOFF);
98 	bts->c_iflag |= cvtto_bsd_mask(lt->c_iflag, LINUX_IMAXBEL, IMAXBEL);
99 
100 	bts->c_oflag = 0;
101 	bts->c_oflag |= cvtto_bsd_mask(lt->c_oflag, LINUX_OPOST, OPOST);
102 	bts->c_oflag |= cvtto_bsd_mask(lt->c_oflag, LINUX_ONLCR, ONLCR);
103 	bts->c_oflag |= cvtto_bsd_mask(lt->c_oflag, LINUX_XTABS, OXTABS);
104 
105 	/*
106 	 * This could have been:
107 	 * bts->c_cflag = (lt->c_flag & LINUX_CSIZE) << 4
108 	 * But who knows, those values might perhaps change one day.
109 	 */
110 	switch (lt->c_cflag & LINUX_CSIZE) {
111 	case LINUX_CS5:
112 		bts->c_cflag = CS5;
113 		break;
114 	case LINUX_CS6:
115 		bts->c_cflag = CS6;
116 		break;
117 	case LINUX_CS7:
118 		bts->c_cflag = CS7;
119 		break;
120 	case LINUX_CS8:
121 		bts->c_cflag = CS8;
122 		break;
123 	}
124 	bts->c_cflag |= cvtto_bsd_mask(lt->c_cflag, LINUX_CSTOPB, CSTOPB);
125 	bts->c_cflag |= cvtto_bsd_mask(lt->c_cflag, LINUX_CREAD, CREAD);
126 	bts->c_cflag |= cvtto_bsd_mask(lt->c_cflag, LINUX_PARENB, PARENB);
127 	bts->c_cflag |= cvtto_bsd_mask(lt->c_cflag, LINUX_PARODD, PARODD);
128 	bts->c_cflag |= cvtto_bsd_mask(lt->c_cflag, LINUX_HUPCL, HUPCL);
129 	bts->c_cflag |= cvtto_bsd_mask(lt->c_cflag, LINUX_CLOCAL, CLOCAL);
130 	bts->c_cflag |= cvtto_bsd_mask(lt->c_cflag, LINUX_CRTSCTS, CRTSCTS);
131 
132 	bts->c_lflag = 0;
133 	bts->c_lflag |= cvtto_bsd_mask(lt->c_lflag, LINUX_ISIG, ISIG);
134 	bts->c_lflag |= cvtto_bsd_mask(lt->c_lflag, LINUX_ICANON, ICANON);
135 	bts->c_lflag |= cvtto_bsd_mask(lt->c_lflag, LINUX_ECHO, ECHO);
136 	bts->c_lflag |= cvtto_bsd_mask(lt->c_lflag, LINUX_ECHOE, ECHOE);
137 	bts->c_lflag |= cvtto_bsd_mask(lt->c_lflag, LINUX_ECHOK, ECHOK);
138 	bts->c_lflag |= cvtto_bsd_mask(lt->c_lflag, LINUX_ECHONL, ECHONL);
139 	bts->c_lflag |= cvtto_bsd_mask(lt->c_lflag, LINUX_NOFLSH, NOFLSH);
140 	bts->c_lflag |= cvtto_bsd_mask(lt->c_lflag, LINUX_TOSTOP, TOSTOP);
141 	bts->c_lflag |= cvtto_bsd_mask(lt->c_lflag, LINUX_ECHOCTL, ECHOCTL);
142 	bts->c_lflag |= cvtto_bsd_mask(lt->c_lflag, LINUX_ECHOPRT, ECHOPRT);
143 	bts->c_lflag |= cvtto_bsd_mask(lt->c_lflag, LINUX_ECHOKE, ECHOKE);
144 	bts->c_lflag |= cvtto_bsd_mask(lt->c_lflag, LINUX_FLUSHO, FLUSHO);
145 	bts->c_lflag |= cvtto_bsd_mask(lt->c_lflag, LINUX_PENDIN, PENDIN);
146 	bts->c_lflag |= cvtto_bsd_mask(lt->c_lflag, LINUX_IEXTEN, IEXTEN);
147 
148 	index = lt->c_cflag & LINUX_CBAUD;
149 	if (index & LINUX_CBAUDEX)
150 		index = (index & ~LINUX_CBAUDEX) + LINUX_NSPEEDS - 1;
151 	bts->c_ispeed = bts->c_ospeed = linux_speeds[index];
152 
153 	bts->c_cc[VINTR] = lt->c_cc[LINUX_VINTR];
154 	bts->c_cc[VQUIT] = lt->c_cc[LINUX_VQUIT];
155 	bts->c_cc[VERASE] = lt->c_cc[LINUX_VERASE];
156 	bts->c_cc[VKILL] = lt->c_cc[LINUX_VKILL];
157 	bts->c_cc[VEOF] = lt->c_cc[LINUX_VEOF];
158 	bts->c_cc[VTIME] = lt->c_cc[LINUX_VTIME];
159 	bts->c_cc[VMIN] = lt->c_cc[LINUX_VMIN];
160 }
161 
162 static int
163 bsd_termios_to_linux_termio(bts, lt)
164 	register struct termios *bts;
165 	register struct linux_termio *lt;
166 {
167 	int i, mask;
168 
169 	lt->c_iflag = 0;
170 	lt->c_iflag |= cvtto_linux_mask(bts->c_iflag, IGNBRK, LINUX_IGNBRK);
171 	lt->c_iflag |= cvtto_linux_mask(bts->c_iflag, BRKINT, LINUX_BRKINT);
172 	lt->c_iflag |= cvtto_linux_mask(bts->c_iflag, IGNPAR, LINUX_IGNPAR);
173 	lt->c_iflag |= cvtto_linux_mask(bts->c_iflag, INPCK, LINUX_INPCK);
174 	lt->c_iflag |= cvtto_linux_mask(bts->c_iflag, ISTRIP, LINUX_ISTRIP);
175 	lt->c_iflag |= cvtto_linux_mask(bts->c_iflag, INLCR, LINUX_INLCR);
176 	lt->c_iflag |= cvtto_linux_mask(bts->c_iflag, IGNCR, LINUX_IGNCR);
177 	lt->c_iflag |= cvtto_linux_mask(bts->c_iflag, ICRNL, LINUX_ICRNL);
178 	lt->c_iflag |= cvtto_linux_mask(bts->c_iflag, IXON, LINUX_IXON);
179 	lt->c_iflag |= cvtto_linux_mask(bts->c_iflag, IXANY, LINUX_IXANY);
180 	lt->c_iflag |= cvtto_linux_mask(bts->c_iflag, IXOFF, LINUX_IXOFF);
181 	lt->c_iflag |= cvtto_linux_mask(bts->c_iflag, IMAXBEL, LINUX_IMAXBEL);
182 
183 	lt->c_oflag = 0;
184 	lt->c_oflag |= cvtto_linux_mask(bts->c_oflag, OPOST, LINUX_OPOST);
185 	lt->c_oflag |= cvtto_linux_mask(bts->c_oflag, ONLCR, LINUX_ONLCR);
186 	lt->c_oflag |= cvtto_linux_mask(bts->c_oflag, OXTABS, LINUX_XTABS);
187 
188 	switch (bts->c_cflag & CSIZE) {
189 	case CS5:
190 		lt->c_cflag = LINUX_CS5;
191 		break;
192 	case CS6:
193 		lt->c_cflag = LINUX_CS6;
194 		break;
195 	case CS7:
196 		lt->c_cflag = LINUX_CS7;
197 		break;
198 	case CS8:
199 		lt->c_cflag = LINUX_CS8;
200 		break;
201 	}
202 	lt->c_cflag |= cvtto_linux_mask(bts->c_cflag, CSTOPB, LINUX_CSTOPB);
203 	lt->c_cflag |= cvtto_linux_mask(bts->c_cflag, CREAD, LINUX_CREAD);
204 	lt->c_cflag |= cvtto_linux_mask(bts->c_cflag, PARENB, LINUX_PARENB);
205 	lt->c_cflag |= cvtto_linux_mask(bts->c_cflag, PARODD, LINUX_PARODD);
206 	lt->c_cflag |= cvtto_linux_mask(bts->c_cflag, HUPCL, LINUX_HUPCL);
207 	lt->c_cflag |= cvtto_linux_mask(bts->c_cflag, CLOCAL, LINUX_CLOCAL);
208 	lt->c_cflag |= cvtto_linux_mask(bts->c_cflag, CRTSCTS, LINUX_CRTSCTS);
209 
210 	lt->c_lflag = 0;
211 	lt->c_lflag |= cvtto_linux_mask(bts->c_lflag, ISIG, LINUX_ISIG);
212 	lt->c_lflag |= cvtto_linux_mask(bts->c_lflag, ICANON, LINUX_ICANON);
213 	lt->c_lflag |= cvtto_linux_mask(bts->c_lflag, ECHO, LINUX_ECHO);
214 	lt->c_lflag |= cvtto_linux_mask(bts->c_lflag, ECHOE, LINUX_ECHOE);
215 	lt->c_lflag |= cvtto_linux_mask(bts->c_lflag, ECHOK, LINUX_ECHOK);
216 	lt->c_lflag |= cvtto_linux_mask(bts->c_lflag, ECHONL, LINUX_ECHONL);
217 	lt->c_lflag |= cvtto_linux_mask(bts->c_lflag, NOFLSH, LINUX_NOFLSH);
218 	lt->c_lflag |= cvtto_linux_mask(bts->c_lflag, TOSTOP, LINUX_TOSTOP);
219 	lt->c_lflag |= cvtto_linux_mask(bts->c_lflag, ECHOCTL, LINUX_ECHOCTL);
220 	lt->c_lflag |= cvtto_linux_mask(bts->c_lflag, ECHOPRT, LINUX_ECHOPRT);
221 	lt->c_lflag |= cvtto_linux_mask(bts->c_lflag, ECHOKE, LINUX_ECHOKE);
222 	lt->c_lflag |= cvtto_linux_mask(bts->c_lflag, FLUSHO, LINUX_FLUSHO);
223 	lt->c_lflag |= cvtto_linux_mask(bts->c_lflag, PENDIN, LINUX_PENDIN);
224 	lt->c_lflag |= cvtto_linux_mask(bts->c_lflag, IEXTEN, LINUX_IEXTEN);
225 
226 	mask = LINUX_B9600;	/* XXX default value should this be 0? */
227 	for (i = 0; i < sizeof (linux_speeds) / sizeof (speed_t); i++) {
228 		if (bts->c_ospeed == linux_speeds[i]) {
229 			mask = linux_spmasks[i];
230 			break;
231 		}
232 	}
233 	lt->c_cflag |= mask;
234 
235 	lt->c_cc[LINUX_VINTR] = bts->c_cc[VINTR];
236 	lt->c_cc[LINUX_VQUIT] = bts->c_cc[VQUIT];
237 	lt->c_cc[LINUX_VERASE] = bts->c_cc[VERASE];
238 	lt->c_cc[LINUX_VKILL] = bts->c_cc[VKILL];
239 	lt->c_cc[LINUX_VEOF] = bts->c_cc[VEOF];
240 	lt->c_cc[LINUX_VTIME] = bts->c_cc[VTIME];
241 	lt->c_cc[LINUX_VMIN] = bts->c_cc[VMIN];
242 	lt->c_cc[LINUX_VSWTC] = 0;
243 
244 	/* XXX should be fixed someday */
245 	lt->c_line = 0;
246 }
247 
248 static int
249 linux_termios_to_bsd_termios(lts, bts)
250 	register struct linux_termios *lts;
251 	register struct termios *bts;
252 {
253 	int index;
254 
255 	bts->c_iflag = 0;
256 	bts->c_iflag |= cvtto_bsd_mask(lts->c_iflag, LINUX_IGNBRK, IGNBRK);
257 	bts->c_iflag |= cvtto_bsd_mask(lts->c_iflag, LINUX_BRKINT, BRKINT);
258 	bts->c_iflag |= cvtto_bsd_mask(lts->c_iflag, LINUX_IGNPAR, IGNPAR);
259 	bts->c_iflag |= cvtto_bsd_mask(lts->c_iflag, LINUX_INPCK, INPCK);
260 	bts->c_iflag |= cvtto_bsd_mask(lts->c_iflag, LINUX_ISTRIP, ISTRIP);
261 	bts->c_iflag |= cvtto_bsd_mask(lts->c_iflag, LINUX_INLCR, INLCR);
262 	bts->c_iflag |= cvtto_bsd_mask(lts->c_iflag, LINUX_IGNCR, IGNCR);
263 	bts->c_iflag |= cvtto_bsd_mask(lts->c_iflag, LINUX_ICRNL, ICRNL);
264 	bts->c_iflag |= cvtto_bsd_mask(lts->c_iflag, LINUX_IXON, IXON);
265 	bts->c_iflag |= cvtto_bsd_mask(lts->c_iflag, LINUX_IXANY, IXANY);
266 	bts->c_iflag |= cvtto_bsd_mask(lts->c_iflag, LINUX_IXOFF, IXOFF);
267 	bts->c_iflag |= cvtto_bsd_mask(lts->c_iflag, LINUX_IMAXBEL, IMAXBEL);
268 
269 	bts->c_oflag = 0;
270 	bts->c_oflag |= cvtto_bsd_mask(lts->c_oflag, LINUX_OPOST, OPOST);
271 	bts->c_oflag |= cvtto_bsd_mask(lts->c_oflag, LINUX_ONLCR, ONLCR);
272 	bts->c_oflag |= cvtto_bsd_mask(lts->c_oflag, LINUX_XTABS, OXTABS);
273 
274 	bts->c_cflag = 0;
275 	switch (lts->c_cflag & LINUX_CSIZE) {
276 	case LINUX_CS5:
277 		bts->c_cflag = CS5;
278 		break;
279 	case LINUX_CS6:
280 		bts->c_cflag = CS6;
281 		break;
282 	case LINUX_CS7:
283 		bts->c_cflag = CS7;
284 		break;
285 	case LINUX_CS8:
286 		bts->c_cflag = CS8;
287 		break;
288 	}
289 	bts->c_cflag |= cvtto_bsd_mask(lts->c_cflag, LINUX_CSTOPB, CSTOPB);
290 	bts->c_cflag |= cvtto_bsd_mask(lts->c_cflag, LINUX_CREAD, CREAD);
291 	bts->c_cflag |= cvtto_bsd_mask(lts->c_cflag, LINUX_PARENB, PARENB);
292 	bts->c_cflag |= cvtto_bsd_mask(lts->c_cflag, LINUX_PARODD, PARODD);
293 	bts->c_cflag |= cvtto_bsd_mask(lts->c_cflag, LINUX_HUPCL, HUPCL);
294 	bts->c_cflag |= cvtto_bsd_mask(lts->c_cflag, LINUX_CLOCAL, CLOCAL);
295 	bts->c_cflag |= cvtto_bsd_mask(lts->c_cflag, LINUX_CRTSCTS, CRTSCTS);
296 
297 	bts->c_lflag = 0;
298 	bts->c_lflag |= cvtto_bsd_mask(lts->c_lflag, LINUX_ISIG, ISIG);
299 	bts->c_lflag |= cvtto_bsd_mask(lts->c_lflag, LINUX_ICANON, ICANON);
300 	bts->c_lflag |= cvtto_bsd_mask(lts->c_lflag, LINUX_ECHO, ECHO);
301 	bts->c_lflag |= cvtto_bsd_mask(lts->c_lflag, LINUX_ECHOE, ECHOE);
302 	bts->c_lflag |= cvtto_bsd_mask(lts->c_lflag, LINUX_ECHOK, ECHOK);
303 	bts->c_lflag |= cvtto_bsd_mask(lts->c_lflag, LINUX_ECHONL, ECHONL);
304 	bts->c_lflag |= cvtto_bsd_mask(lts->c_lflag, LINUX_NOFLSH, NOFLSH);
305 	bts->c_lflag |= cvtto_bsd_mask(lts->c_lflag, LINUX_TOSTOP, TOSTOP);
306 	bts->c_lflag |= cvtto_bsd_mask(lts->c_lflag, LINUX_ECHOCTL, ECHOCTL);
307 	bts->c_lflag |= cvtto_bsd_mask(lts->c_lflag, LINUX_ECHOPRT, ECHOPRT);
308 	bts->c_lflag |= cvtto_bsd_mask(lts->c_lflag, LINUX_ECHOKE, ECHOKE);
309 	bts->c_lflag |= cvtto_bsd_mask(lts->c_lflag, LINUX_FLUSHO, FLUSHO);
310 	bts->c_lflag |= cvtto_bsd_mask(lts->c_lflag, LINUX_PENDIN, PENDIN);
311 	bts->c_lflag |= cvtto_bsd_mask(lts->c_lflag, LINUX_IEXTEN, IEXTEN);
312 
313 	index = lts->c_cflag & LINUX_CBAUD;
314 	if (index & LINUX_CBAUDEX)
315 		index = (index & ~LINUX_CBAUDEX) + LINUX_NSPEEDS - 1;
316 	bts->c_ispeed = bts->c_ospeed = linux_speeds[index];
317 
318 	bts->c_cc[VINTR] = lts->c_cc[LINUX_VINTR];
319 	bts->c_cc[VQUIT] = lts->c_cc[LINUX_VQUIT];
320 	bts->c_cc[VERASE] = lts->c_cc[LINUX_VERASE];
321 	bts->c_cc[VKILL] = lts->c_cc[LINUX_VKILL];
322 	bts->c_cc[VEOF] = lts->c_cc[LINUX_VEOF];
323 	bts->c_cc[VTIME] = lts->c_cc[LINUX_VTIME];
324 	bts->c_cc[VMIN] = lts->c_cc[LINUX_VMIN];
325 	bts->c_cc[VEOL] = lts->c_cc[LINUX_VEOL];
326 	bts->c_cc[VEOL2] = lts->c_cc[LINUX_VEOL2];
327 	bts->c_cc[VWERASE] = lts->c_cc[LINUX_VWERASE];
328 	bts->c_cc[VSUSP] = lts->c_cc[LINUX_VSUSP];
329 	bts->c_cc[VSTART] = lts->c_cc[LINUX_VSTART];
330 	bts->c_cc[VSTOP] = lts->c_cc[LINUX_VSTOP];
331 	bts->c_cc[VLNEXT] = lts->c_cc[LINUX_VLNEXT];
332 	bts->c_cc[VDISCARD] = lts->c_cc[LINUX_VDISCARD];
333 	bts->c_cc[VREPRINT] = lts->c_cc[LINUX_VREPRINT];
334 }
335 
336 static int
337 bsd_termios_to_linux_termios(bts, lts)
338 	register struct termios *bts;
339 	register struct linux_termios *lts;
340 {
341 	int i, mask;
342 
343 	lts->c_iflag = 0;
344 	lts->c_iflag |= cvtto_linux_mask(bts->c_iflag, IGNBRK, LINUX_IGNBRK);
345 	lts->c_iflag |= cvtto_linux_mask(bts->c_iflag, BRKINT, LINUX_BRKINT);
346 	lts->c_iflag |= cvtto_linux_mask(bts->c_iflag, IGNPAR, LINUX_IGNPAR);
347 	lts->c_iflag |= cvtto_linux_mask(bts->c_iflag, INPCK, LINUX_INPCK);
348 	lts->c_iflag |= cvtto_linux_mask(bts->c_iflag, ISTRIP, LINUX_ISTRIP);
349 	lts->c_iflag |= cvtto_linux_mask(bts->c_iflag, INLCR, LINUX_INLCR);
350 	lts->c_iflag |= cvtto_linux_mask(bts->c_iflag, IGNCR, LINUX_IGNCR);
351 	lts->c_iflag |= cvtto_linux_mask(bts->c_iflag, ICRNL, LINUX_ICRNL);
352 	lts->c_iflag |= cvtto_linux_mask(bts->c_iflag, IXON, LINUX_IXON);
353 	lts->c_iflag |= cvtto_linux_mask(bts->c_iflag, IXANY, LINUX_IXANY);
354 	lts->c_iflag |= cvtto_linux_mask(bts->c_iflag, IXOFF, LINUX_IXOFF);
355 	lts->c_iflag |= cvtto_linux_mask(bts->c_iflag, IMAXBEL, LINUX_IMAXBEL);
356 
357 	lts->c_oflag = 0;
358 	lts->c_oflag |= cvtto_linux_mask(bts->c_oflag, OPOST, LINUX_OPOST);
359 	lts->c_oflag |= cvtto_linux_mask(bts->c_oflag, ONLCR, LINUX_ONLCR);
360 	lts->c_oflag |= cvtto_linux_mask(bts->c_oflag, OXTABS, LINUX_XTABS);
361 
362 	switch (bts->c_cflag & CSIZE) {
363 	case CS5:
364 		lts->c_cflag = LINUX_CS5;
365 		break;
366 	case CS6:
367 		lts->c_cflag = LINUX_CS6;
368 		break;
369 	case CS7:
370 		lts->c_cflag = LINUX_CS7;
371 		break;
372 	case CS8:
373 		lts->c_cflag = LINUX_CS8;
374 		break;
375 	}
376 	lts->c_cflag |= cvtto_linux_mask(bts->c_cflag, CS5, LINUX_CS5);
377 	lts->c_cflag |= cvtto_linux_mask(bts->c_cflag, CS6, LINUX_CS6);
378 	lts->c_cflag |= cvtto_linux_mask(bts->c_cflag, CS7, LINUX_CS7);
379 	lts->c_cflag |= cvtto_linux_mask(bts->c_cflag, CS8, LINUX_CS8);
380 	lts->c_cflag |= cvtto_linux_mask(bts->c_cflag, CSTOPB, LINUX_CSTOPB);
381 	lts->c_cflag |= cvtto_linux_mask(bts->c_cflag, CREAD, LINUX_CREAD);
382 	lts->c_cflag |= cvtto_linux_mask(bts->c_cflag, PARENB, LINUX_PARENB);
383 	lts->c_cflag |= cvtto_linux_mask(bts->c_cflag, PARODD, LINUX_PARODD);
384 	lts->c_cflag |= cvtto_linux_mask(bts->c_cflag, HUPCL, LINUX_HUPCL);
385 	lts->c_cflag |= cvtto_linux_mask(bts->c_cflag, CLOCAL, LINUX_CLOCAL);
386 	lts->c_cflag |= cvtto_linux_mask(bts->c_cflag, CRTSCTS, LINUX_CRTSCTS);
387 
388 	lts->c_lflag = 0;
389 	lts->c_lflag |= cvtto_linux_mask(bts->c_lflag, ISIG, LINUX_ISIG);
390 	lts->c_lflag |= cvtto_linux_mask(bts->c_lflag, ICANON, LINUX_ICANON);
391 	lts->c_lflag |= cvtto_linux_mask(bts->c_lflag, ECHO, LINUX_ECHO);
392 	lts->c_lflag |= cvtto_linux_mask(bts->c_lflag, ECHOE, LINUX_ECHOE);
393 	lts->c_lflag |= cvtto_linux_mask(bts->c_lflag, ECHOK, LINUX_ECHOK);
394 	lts->c_lflag |= cvtto_linux_mask(bts->c_lflag, ECHONL, LINUX_ECHONL);
395 	lts->c_lflag |= cvtto_linux_mask(bts->c_lflag, NOFLSH, LINUX_NOFLSH);
396 	lts->c_lflag |= cvtto_linux_mask(bts->c_lflag, TOSTOP, LINUX_TOSTOP);
397 	lts->c_lflag |= cvtto_linux_mask(bts->c_lflag, ECHOCTL, LINUX_ECHOCTL);
398 	lts->c_lflag |= cvtto_linux_mask(bts->c_lflag, ECHOPRT, LINUX_ECHOPRT);
399 	lts->c_lflag |= cvtto_linux_mask(bts->c_lflag, ECHOKE, LINUX_ECHOKE);
400 	lts->c_lflag |= cvtto_linux_mask(bts->c_lflag, FLUSHO, LINUX_FLUSHO);
401 	lts->c_lflag |= cvtto_linux_mask(bts->c_lflag, PENDIN, LINUX_PENDIN);
402 	lts->c_lflag |= cvtto_linux_mask(bts->c_lflag, IEXTEN, LINUX_IEXTEN);
403 
404 	mask = LINUX_B9600;	/* XXX default value */
405 	for (i = 0; i < sizeof (linux_speeds) / sizeof (speed_t); i++) {
406 		if (bts->c_ospeed == linux_speeds[i]) {
407 			mask = linux_spmasks[i];
408 			break;
409 		}
410 	}
411 	lts->c_cflag |= mask;
412 
413 	lts->c_cc[LINUX_VINTR] = bts->c_cc[VINTR];
414 	lts->c_cc[LINUX_VQUIT] = bts->c_cc[VQUIT];
415 	lts->c_cc[LINUX_VERASE] = bts->c_cc[VERASE];
416 	lts->c_cc[LINUX_VKILL] = bts->c_cc[VKILL];
417 	lts->c_cc[LINUX_VEOF] = bts->c_cc[VEOF];
418 	lts->c_cc[LINUX_VTIME] = bts->c_cc[VTIME];
419 	lts->c_cc[LINUX_VMIN] = bts->c_cc[VMIN];
420 	lts->c_cc[LINUX_VEOL] = bts->c_cc[VEOL];
421 	lts->c_cc[LINUX_VEOL2] = bts->c_cc[VEOL2];
422 	lts->c_cc[LINUX_VWERASE] = bts->c_cc[VWERASE];
423 	lts->c_cc[LINUX_VSUSP] = bts->c_cc[VSUSP];
424 	lts->c_cc[LINUX_VSTART] = bts->c_cc[VSTART];
425 	lts->c_cc[LINUX_VSTOP] = bts->c_cc[VSTOP];
426 	lts->c_cc[LINUX_VLNEXT] = bts->c_cc[VLNEXT];
427 	lts->c_cc[LINUX_VDISCARD] = bts->c_cc[VDISCARD];
428 	lts->c_cc[LINUX_VREPRINT] = bts->c_cc[VREPRINT];
429 	lts->c_cc[LINUX_VSWTC] = 0;
430 
431 	/* XXX should be fixed someday */
432 	lts->c_line = 0;
433 }
434 
435 /*
436  * Most ioctl command are just converted to their NetBSD values,
437  * and passed on. The ones that take structure pointers and (flag)
438  * values need some massaging. This is done the usual way by
439  * allocating stackgap memory, letting the actual ioctl call do its
440  * work their and converting back the data afterwards.
441  */
442 int
443 linux_sys_ioctl(p, v, retval)
444 	register struct proc *p;
445 	void *v;
446 	register_t *retval;
447 {
448 	register struct linux_sys_ioctl_args /* {
449 		syscallarg(int) fd;
450 		syscallarg(u_long) com;
451 		syscallarg(caddr_t) data;
452 	} */ *uap = v;
453 	int fd;
454 	unsigned long com;
455 	caddr_t data, sg;
456 	struct file *fp;
457 	struct filedesc *fdp;
458 	struct linux_termio tmplt, *alt;
459 	struct linux_termios tmplts, *alts;
460 	struct termios tmpbts, *abts;
461 	struct sys_ioctl_args ia;
462 	int error, idat, *idatp;
463 
464 	fd = SCARG(&ia, fd) = SCARG(uap, fd);
465 	com = SCARG(uap, com);
466 	data = SCARG(&ia, data) = SCARG(uap, data);
467 	retval[0] = 0;
468 
469 	fdp = p->p_fd;
470 	if ((u_int)fd >= fdp->fd_nfiles ||
471 	    (fp = fdp->fd_ofiles[fd]) == NULL)
472 		return (EBADF);
473 
474 	if ((fp->f_flag & (FREAD | FWRITE)) == 0)
475 		return (EBADF);
476 
477 	sg = stackgap_init(p->p_emul);
478 
479 	switch (com) {
480 	case LINUX_TCGETS:
481 		SCARG(&ia, com) = TIOCGETA;
482 		abts = stackgap_alloc(&sg, sizeof (*abts));
483 		SCARG(&ia, data) = (caddr_t) abts;
484 		if ((error = sys_ioctl(p, &ia, retval)) != 0)
485 			return error;
486 		if ((error = copyin(abts, &tmpbts, sizeof tmpbts)))
487 			return error;
488 		bsd_termios_to_linux_termios(&tmpbts, &tmplts);
489 		return copyout(&tmplts, data, sizeof tmplts);
490 	case LINUX_TCSETS:
491 	case LINUX_TCSETSW:
492 	case LINUX_TCSETSF:
493 		switch (com) {
494 		case LINUX_TCSETS:
495 			SCARG(&ia, com) = TIOCSETA;
496 			break;
497 		case LINUX_TCSETSW:
498 			SCARG(&ia, com) = TIOCSETAW;
499 			break;
500 		case LINUX_TCSETSF:
501 			SCARG(&ia, com) = TIOCSETAF;
502 			break;
503 		}
504 		if ((error = copyin(data, &tmplts, sizeof tmplts)))
505 			return error;
506 		abts = stackgap_alloc(&sg, sizeof tmpbts);
507 		/*
508 		 * First fill in all fields, so that we keep the current
509 		 * values for fields that Linux doesn't know about.
510 		 */
511 		if ((error = (*fp->f_ops->fo_ioctl)(fp, TIOCGETA,
512 		    (caddr_t) &tmpbts, p)))
513 			return error;
514 		linux_termios_to_bsd_termios(&tmplts, &tmpbts);
515 		if ((error = copyout(&tmpbts, abts, sizeof tmpbts)))
516 			return error;
517 		SCARG(&ia, data) = (caddr_t) abts;
518 		return sys_ioctl(p, &ia, retval);
519 	case LINUX_TCGETA:
520 		SCARG(&ia, com) = TIOCGETA;
521 		abts = stackgap_alloc(&sg, sizeof (*abts));
522 		SCARG(&ia, data) = (caddr_t) abts;
523 		if ((error = sys_ioctl(p, &ia, retval)) != 0)
524 			return error;
525 		if ((error = copyin(abts, &tmpbts, sizeof tmpbts)))
526 			return error;
527 		bsd_termios_to_linux_termio(&tmpbts, &tmplt);
528 		return copyout(&tmplt, data, sizeof tmplt);
529 	case LINUX_TCSETA:
530 	case LINUX_TCSETAW:
531 	case LINUX_TCSETAF:
532 		switch (com) {
533 		case LINUX_TCSETA:
534 			SCARG(&ia, com) = TIOCSETA;
535 			break;
536 		case LINUX_TCSETAW:
537 			SCARG(&ia, com) = TIOCSETAW;
538 			break;
539 		case LINUX_TCSETAF:
540 			SCARG(&ia, com) = TIOCSETAF;
541 			break;
542 		}
543 		if ((error = copyin(data, &tmplt, sizeof tmplt)))
544 			return error;
545 		abts = stackgap_alloc(&sg, sizeof tmpbts);
546 		/*
547 		 * First fill in all fields, so that we keep the current
548 		 * values for fields that Linux doesn't know about.
549 		 */
550 		if ((error = (*fp->f_ops->fo_ioctl)(fp, TIOCGETA,
551 		    (caddr_t) &tmpbts, p)))
552 			return error;
553 		linux_termio_to_bsd_termios(&tmplt, &tmpbts);
554 		if ((error = copyout(&tmpbts, abts, sizeof tmpbts)))
555 			return error;
556 		SCARG(&ia, data) = (caddr_t) abts;
557 		return sys_ioctl(p, &ia, retval);
558 	case LINUX_TIOCSETD:
559 		if ((error = copyin(data, (caddr_t) &idat, sizeof idat)))
560 			return error;
561 		switch (idat) {
562 		case LINUX_N_TTY:
563 			idat = TTYDISC;
564 			break;
565 		case LINUX_N_SLIP:
566 			idat = SLIPDISC;
567 			break;
568 		case LINUX_N_PPP:
569 			idat = PPPDISC;
570 			break;
571 		/*
572 		 * We can't handle the mouse line discipline Linux has.
573 		 */
574 		case LINUX_N_MOUSE:
575 		default:
576 			return EINVAL;
577 		}
578 
579 		idatp = (int *) stackgap_alloc(&sg, sizeof (int));
580 		if ((error = copyout(&idat, idatp, sizeof (int))))
581 			return error;
582 		SCARG(&ia, com) = TIOCSETD;
583 		SCARG(&ia, data) = (caddr_t) idatp;
584 		break;
585 	case LINUX_TIOCGETD:
586 		idatp = (int *) stackgap_alloc(&sg, sizeof (int));
587 		SCARG(&ia, com) = TIOCGETD;
588 		SCARG(&ia, data) = (caddr_t) idatp;
589 		if ((error = sys_ioctl(p, &ia, retval)))
590 			return error;
591 		if ((error = copyin(idatp, (caddr_t) &idat, sizeof (int))))
592 			return error;
593 		switch (idat) {
594 		case TTYDISC:
595 			idat = LINUX_N_TTY;
596 			break;
597 		case SLIPDISC:
598 			idat = LINUX_N_SLIP;
599 			break;
600 		case PPPDISC:
601 			idat = LINUX_N_PPP;
602 			break;
603 		/*
604 		 * Linux does not have the tablet line discipline.
605 		 */
606 		case TABLDISC:
607 		default:
608 			idat = -1;	/* XXX What should this be? */
609 			break;
610 		}
611 		return copyout(&idat, data, sizeof (int));
612 	case LINUX_TIOCGWINSZ:
613 		SCARG(&ia, com) = TIOCGWINSZ;
614 		break;
615 	case LINUX_TIOCSWINSZ:
616 		SCARG(&ia, com) = TIOCSWINSZ;
617 		break;
618 	case LINUX_TIOCGPGRP:
619 		SCARG(&ia, com) = TIOCGPGRP;
620 		break;
621 	case LINUX_TIOCSPGRP:
622 		SCARG(&ia, com) = TIOCSPGRP;
623 		break;
624 	case LINUX_FIONREAD:
625 		SCARG(&ia, com) = FIONREAD;
626 		break;
627 	case LINUX_FIONBIO:
628 		SCARG(&ia, com) = FIONBIO;
629 		break;
630 	case LINUX_FIOASYNC:
631 		SCARG(&ia, com) = FIOASYNC;
632 		break;
633 	case LINUX_TIOCEXCL:
634 		SCARG(&ia, com) = TIOCEXCL;
635 		break;
636 	case LINUX_TIOCNXCL:
637 		SCARG(&ia, com) = TIOCNXCL;
638 		break;
639 	case LINUX_TIOCCONS:
640 		SCARG(&ia, com) = TIOCCONS;
641 		break;
642 	case LINUX_TIOCNOTTY:
643 		SCARG(&ia, com) = TIOCNOTTY;
644 		break;
645 	case LINUX_SIOCADDMULTI:
646 		SCARG(&ia, com) = SIOCADDMULTI;
647 		break;
648 	case LINUX_SIOCDELMULTI:
649 		SCARG(&ia, com) = SIOCDELMULTI;
650 		break;
651 	default:
652 		return linux_machdepioctl(p, uap, retval);
653 	}
654 
655 	return sys_ioctl(p, &ia, retval);
656 }
657