xref: /freebsd/sys/compat/linux/linux_ioctl.c (revision 68344a95478e7f7a30cc2d93820595aad7e7bc5b)
1 /*
2  * Copyright (c) 1994-1995 S�ren Schmidt
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer
10  *    in this position and unchanged.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. The name of the author may not be used to endorse or promote products
15  *    derived from this software withough specific prior written permission
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * $FreeBSD$
29  */
30 
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/sysproto.h>
34 #include <sys/cdio.h>
35 #include <sys/consio.h>
36 #include <sys/ctype.h>
37 #include <sys/disklabel.h>
38 #include <sys/fcntl.h>
39 #include <sys/file.h>
40 #include <sys/filedesc.h>
41 #include <sys/filio.h>
42 #include <sys/kbio.h>
43 #include <sys/linker_set.h>
44 #include <sys/malloc.h>
45 #include <sys/proc.h>
46 #include <sys/socket.h>
47 #include <sys/sockio.h>
48 #include <sys/soundcard.h>
49 #include <sys/tty.h>
50 #include <sys/uio.h>
51 #include <net/if.h>
52 #include <net/if_dl.h>
53 #include <net/if_types.h>
54 
55 #include <machine/../linux/linux.h>
56 #include <machine/../linux/linux_proto.h>
57 
58 #include <compat/linux/linux_ioctl.h>
59 #include <compat/linux/linux_mib.h>
60 #include <compat/linux/linux_util.h>
61 
62 static linux_ioctl_function_t linux_ioctl_cdrom;
63 static linux_ioctl_function_t linux_ioctl_console;
64 static linux_ioctl_function_t linux_ioctl_disk;
65 static linux_ioctl_function_t linux_ioctl_socket;
66 static linux_ioctl_function_t linux_ioctl_sound;
67 static linux_ioctl_function_t linux_ioctl_termio;
68 static linux_ioctl_function_t linux_ioctl_private;
69 
70 static struct linux_ioctl_handler cdrom_handler =
71 { linux_ioctl_cdrom, LINUX_IOCTL_CDROM_MIN, LINUX_IOCTL_CDROM_MAX };
72 static struct linux_ioctl_handler console_handler =
73 { linux_ioctl_console, LINUX_IOCTL_CONSOLE_MIN, LINUX_IOCTL_CONSOLE_MAX };
74 static struct linux_ioctl_handler disk_handler =
75 { linux_ioctl_disk, LINUX_IOCTL_DISK_MIN, LINUX_IOCTL_DISK_MAX };
76 static struct linux_ioctl_handler socket_handler =
77 { linux_ioctl_socket, LINUX_IOCTL_SOCKET_MIN, LINUX_IOCTL_SOCKET_MAX };
78 static struct linux_ioctl_handler sound_handler =
79 { linux_ioctl_sound, LINUX_IOCTL_SOUND_MIN, LINUX_IOCTL_SOUND_MAX };
80 static struct linux_ioctl_handler termio_handler =
81 { linux_ioctl_termio, LINUX_IOCTL_TERMIO_MIN, LINUX_IOCTL_TERMIO_MAX };
82 static struct linux_ioctl_handler private_handler =
83 { linux_ioctl_private, LINUX_IOCTL_PRIVATE_MIN, LINUX_IOCTL_PRIVATE_MAX };
84 
85 DATA_SET(linux_ioctl_handler_set, cdrom_handler);
86 DATA_SET(linux_ioctl_handler_set, console_handler);
87 DATA_SET(linux_ioctl_handler_set, disk_handler);
88 DATA_SET(linux_ioctl_handler_set, socket_handler);
89 DATA_SET(linux_ioctl_handler_set, sound_handler);
90 DATA_SET(linux_ioctl_handler_set, termio_handler);
91 DATA_SET(linux_ioctl_handler_set, private_handler);
92 
93 struct handler_element
94 {
95 	TAILQ_ENTRY(handler_element) list;
96 	int	(*func)(struct thread *, struct linux_ioctl_args *);
97 	int	low, high, span;
98 };
99 
100 static TAILQ_HEAD(, handler_element) handlers =
101 	TAILQ_HEAD_INITIALIZER(handlers);
102 
103 static int
104 linux_ioctl_disk(struct thread *td, struct linux_ioctl_args *args)
105 {
106 	struct file *fp = td->td_proc->p_fd->fd_ofiles[args->fd];
107 	int error;
108 	struct disklabel dl;
109 
110 	switch (args->cmd & 0xffff) {
111 	case LINUX_BLKGETSIZE:
112 		error = fo_ioctl(fp, DIOCGDINFO, (caddr_t)&dl, td);
113 		if (error)
114 			return (error);
115 		return (copyout(&(dl.d_secperunit), (caddr_t)args->arg,
116 		     sizeof(dl.d_secperunit)));
117 		break;
118 	}
119 	return (ENOIOCTL);
120 }
121 
122 /*
123  * termio related ioctls
124  */
125 
126 struct linux_termio {
127 	unsigned short c_iflag;
128 	unsigned short c_oflag;
129 	unsigned short c_cflag;
130 	unsigned short c_lflag;
131 	unsigned char c_line;
132 	unsigned char c_cc[LINUX_NCC];
133 };
134 
135 struct linux_termios {
136 	unsigned int c_iflag;
137 	unsigned int c_oflag;
138 	unsigned int c_cflag;
139 	unsigned int c_lflag;
140 #ifdef __alpha__
141 	unsigned char c_cc[LINUX_NCCS];
142 	unsigned char c_line;
143 	unsigned int  c_ispeed;
144 	unsigned int  c_ospeed;
145 #else
146 	unsigned char c_line;
147 	unsigned char c_cc[LINUX_NCCS];
148 #endif
149 };
150 
151 struct linux_winsize {
152 	unsigned short ws_row, ws_col;
153 	unsigned short ws_xpixel, ws_ypixel;
154 };
155 
156 static struct speedtab sptab[] = {
157 	{ B0, LINUX_B0 }, { B50, LINUX_B50 },
158 	{ B75, LINUX_B75 }, { B110, LINUX_B110 },
159 	{ B134, LINUX_B134 }, { B150, LINUX_B150 },
160 	{ B200, LINUX_B200 }, { B300, LINUX_B300 },
161 	{ B600, LINUX_B600 }, { B1200, LINUX_B1200 },
162 	{ B1800, LINUX_B1800 }, { B2400, LINUX_B2400 },
163 	{ B4800, LINUX_B4800 }, { B9600, LINUX_B9600 },
164 	{ B19200, LINUX_B19200 }, { B38400, LINUX_B38400 },
165 	{ B57600, LINUX_B57600 }, { B115200, LINUX_B115200 },
166 	{-1, -1 }
167 };
168 
169 struct linux_serial_struct {
170 	int	type;
171 	int	line;
172 	int	port;
173 	int	irq;
174 	int	flags;
175 	int	xmit_fifo_size;
176 	int	custom_divisor;
177 	int	baud_base;
178 	unsigned short close_delay;
179 	char	reserved_char[2];
180 	int	hub6;
181 	unsigned short closing_wait;
182 	unsigned short closing_wait2;
183 	int	reserved[4];
184 };
185 
186 static int
187 linux_to_bsd_speed(int code, struct speedtab *table)
188 {
189 	for ( ; table->sp_code != -1; table++)
190 		if (table->sp_code == code)
191 			return (table->sp_speed);
192 	return -1;
193 }
194 
195 static int
196 bsd_to_linux_speed(int speed, struct speedtab *table)
197 {
198 	for ( ; table->sp_speed != -1; table++)
199 		if (table->sp_speed == speed)
200 			return (table->sp_code);
201 	return -1;
202 }
203 
204 static void
205 bsd_to_linux_termios(struct termios *bios, struct linux_termios *lios)
206 {
207 	int i;
208 
209 #ifdef DEBUG
210 	if (ldebug(ioctl)) {
211 		printf("LINUX: BSD termios structure (input):\n");
212 		printf("i=%08x o=%08x c=%08x l=%08x ispeed=%d ospeed=%d\n",
213 		    bios->c_iflag, bios->c_oflag, bios->c_cflag, bios->c_lflag,
214 		    bios->c_ispeed, bios->c_ospeed);
215 		printf("c_cc ");
216 		for (i=0; i<NCCS; i++)
217 			printf("%02x ", bios->c_cc[i]);
218 		printf("\n");
219 	}
220 #endif
221 
222 	lios->c_iflag = 0;
223 	if (bios->c_iflag & IGNBRK)
224 		lios->c_iflag |= LINUX_IGNBRK;
225 	if (bios->c_iflag & BRKINT)
226 		lios->c_iflag |= LINUX_BRKINT;
227 	if (bios->c_iflag & IGNPAR)
228 		lios->c_iflag |= LINUX_IGNPAR;
229 	if (bios->c_iflag & PARMRK)
230 		lios->c_iflag |= LINUX_PARMRK;
231 	if (bios->c_iflag & INPCK)
232 		lios->c_iflag |= LINUX_INPCK;
233 	if (bios->c_iflag & ISTRIP)
234 		lios->c_iflag |= LINUX_ISTRIP;
235 	if (bios->c_iflag & INLCR)
236 		lios->c_iflag |= LINUX_INLCR;
237 	if (bios->c_iflag & IGNCR)
238 		lios->c_iflag |= LINUX_IGNCR;
239 	if (bios->c_iflag & ICRNL)
240 		lios->c_iflag |= LINUX_ICRNL;
241 	if (bios->c_iflag & IXON)
242 		lios->c_iflag |= LINUX_IXON;
243 	if (bios->c_iflag & IXANY)
244 		lios->c_iflag |= LINUX_IXANY;
245 	if (bios->c_iflag & IXOFF)
246 		lios->c_iflag |= LINUX_IXOFF;
247 	if (bios->c_iflag & IMAXBEL)
248 		lios->c_iflag |= LINUX_IMAXBEL;
249 
250 	lios->c_oflag = 0;
251 	if (bios->c_oflag & OPOST)
252 		lios->c_oflag |= LINUX_OPOST;
253 	if (bios->c_oflag & ONLCR)
254 		lios->c_oflag |= LINUX_ONLCR;
255 	if (bios->c_oflag & OXTABS)
256 		lios->c_oflag |= LINUX_XTABS;
257 
258 	lios->c_cflag = bsd_to_linux_speed(bios->c_ispeed, sptab);
259 	lios->c_cflag |= (bios->c_cflag & CSIZE) >> 4;
260 	if (bios->c_cflag & CSTOPB)
261 		lios->c_cflag |= LINUX_CSTOPB;
262 	if (bios->c_cflag & CREAD)
263 		lios->c_cflag |= LINUX_CREAD;
264 	if (bios->c_cflag & PARENB)
265 		lios->c_cflag |= LINUX_PARENB;
266 	if (bios->c_cflag & PARODD)
267 		lios->c_cflag |= LINUX_PARODD;
268 	if (bios->c_cflag & HUPCL)
269 		lios->c_cflag |= LINUX_HUPCL;
270 	if (bios->c_cflag & CLOCAL)
271 		lios->c_cflag |= LINUX_CLOCAL;
272 	if (bios->c_cflag & CRTSCTS)
273 		lios->c_cflag |= LINUX_CRTSCTS;
274 
275 	lios->c_lflag = 0;
276 	if (bios->c_lflag & ISIG)
277 		lios->c_lflag |= LINUX_ISIG;
278 	if (bios->c_lflag & ICANON)
279 		lios->c_lflag |= LINUX_ICANON;
280 	if (bios->c_lflag & ECHO)
281 		lios->c_lflag |= LINUX_ECHO;
282 	if (bios->c_lflag & ECHOE)
283 		lios->c_lflag |= LINUX_ECHOE;
284 	if (bios->c_lflag & ECHOK)
285 		lios->c_lflag |= LINUX_ECHOK;
286 	if (bios->c_lflag & ECHONL)
287 		lios->c_lflag |= LINUX_ECHONL;
288 	if (bios->c_lflag & NOFLSH)
289 		lios->c_lflag |= LINUX_NOFLSH;
290 	if (bios->c_lflag & TOSTOP)
291 		lios->c_lflag |= LINUX_TOSTOP;
292 	if (bios->c_lflag & ECHOCTL)
293 		lios->c_lflag |= LINUX_ECHOCTL;
294 	if (bios->c_lflag & ECHOPRT)
295 		lios->c_lflag |= LINUX_ECHOPRT;
296 	if (bios->c_lflag & ECHOKE)
297 		lios->c_lflag |= LINUX_ECHOKE;
298 	if (bios->c_lflag & FLUSHO)
299 		lios->c_lflag |= LINUX_FLUSHO;
300 	if (bios->c_lflag & PENDIN)
301 		lios->c_lflag |= LINUX_PENDIN;
302 	if (bios->c_lflag & IEXTEN)
303 		lios->c_lflag |= LINUX_IEXTEN;
304 
305 	for (i=0; i<LINUX_NCCS; i++)
306 		lios->c_cc[i] = LINUX_POSIX_VDISABLE;
307 	lios->c_cc[LINUX_VINTR] = bios->c_cc[VINTR];
308 	lios->c_cc[LINUX_VQUIT] = bios->c_cc[VQUIT];
309 	lios->c_cc[LINUX_VERASE] = bios->c_cc[VERASE];
310 	lios->c_cc[LINUX_VKILL] = bios->c_cc[VKILL];
311 	lios->c_cc[LINUX_VEOF] = bios->c_cc[VEOF];
312 	lios->c_cc[LINUX_VEOL] = bios->c_cc[VEOL];
313 	lios->c_cc[LINUX_VMIN] = bios->c_cc[VMIN];
314 	lios->c_cc[LINUX_VTIME] = bios->c_cc[VTIME];
315 	lios->c_cc[LINUX_VEOL2] = bios->c_cc[VEOL2];
316 	lios->c_cc[LINUX_VSUSP] = bios->c_cc[VSUSP];
317 	lios->c_cc[LINUX_VSTART] = bios->c_cc[VSTART];
318 	lios->c_cc[LINUX_VSTOP] = bios->c_cc[VSTOP];
319 	lios->c_cc[LINUX_VREPRINT] = bios->c_cc[VREPRINT];
320 	lios->c_cc[LINUX_VDISCARD] = bios->c_cc[VDISCARD];
321 	lios->c_cc[LINUX_VWERASE] = bios->c_cc[VWERASE];
322 	lios->c_cc[LINUX_VLNEXT] = bios->c_cc[VLNEXT];
323 
324 	for (i=0; i<LINUX_NCCS; i++) {
325 		if (lios->c_cc[i] == _POSIX_VDISABLE)
326 			lios->c_cc[i] = LINUX_POSIX_VDISABLE;
327 	}
328 	lios->c_line = 0;
329 
330 #ifdef DEBUG
331 	if (ldebug(ioctl)) {
332 		printf("LINUX: LINUX termios structure (output):\n");
333 		printf("i=%08x o=%08x c=%08x l=%08x line=%d\n",
334 		    lios->c_iflag, lios->c_oflag, lios->c_cflag,
335 		    lios->c_lflag, (int)lios->c_line);
336 		printf("c_cc ");
337 		for (i=0; i<LINUX_NCCS; i++)
338 			printf("%02x ", lios->c_cc[i]);
339 		printf("\n");
340 	}
341 #endif
342 }
343 
344 static void
345 linux_to_bsd_termios(struct linux_termios *lios, struct termios *bios)
346 {
347 	int i;
348 
349 #ifdef DEBUG
350 	if (ldebug(ioctl)) {
351 		printf("LINUX: LINUX termios structure (input):\n");
352 		printf("i=%08x o=%08x c=%08x l=%08x line=%d\n",
353 		    lios->c_iflag, lios->c_oflag, lios->c_cflag,
354 		    lios->c_lflag, (int)lios->c_line);
355 		printf("c_cc ");
356 		for (i=0; i<LINUX_NCCS; i++)
357 			printf("%02x ", lios->c_cc[i]);
358 		printf("\n");
359 	}
360 #endif
361 
362 	bios->c_iflag = 0;
363 	if (lios->c_iflag & LINUX_IGNBRK)
364 		bios->c_iflag |= IGNBRK;
365 	if (lios->c_iflag & LINUX_BRKINT)
366 		bios->c_iflag |= BRKINT;
367 	if (lios->c_iflag & LINUX_IGNPAR)
368 		bios->c_iflag |= IGNPAR;
369 	if (lios->c_iflag & LINUX_PARMRK)
370 		bios->c_iflag |= PARMRK;
371 	if (lios->c_iflag & LINUX_INPCK)
372 		bios->c_iflag |= INPCK;
373 	if (lios->c_iflag & LINUX_ISTRIP)
374 		bios->c_iflag |= ISTRIP;
375 	if (lios->c_iflag & LINUX_INLCR)
376 		bios->c_iflag |= INLCR;
377 	if (lios->c_iflag & LINUX_IGNCR)
378 		bios->c_iflag |= IGNCR;
379 	if (lios->c_iflag & LINUX_ICRNL)
380 		bios->c_iflag |= ICRNL;
381 	if (lios->c_iflag & LINUX_IXON)
382 		bios->c_iflag |= IXON;
383 	if (lios->c_iflag & LINUX_IXANY)
384 		bios->c_iflag |= IXANY;
385 	if (lios->c_iflag & LINUX_IXOFF)
386 		bios->c_iflag |= IXOFF;
387 	if (lios->c_iflag & LINUX_IMAXBEL)
388 		bios->c_iflag |= IMAXBEL;
389 
390 	bios->c_oflag = 0;
391 	if (lios->c_oflag & LINUX_OPOST)
392 		bios->c_oflag |= OPOST;
393 	if (lios->c_oflag & LINUX_ONLCR)
394 		bios->c_oflag |= ONLCR;
395 	if (lios->c_oflag & LINUX_XTABS)
396 		bios->c_oflag |= OXTABS;
397 
398 	bios->c_cflag = (lios->c_cflag & LINUX_CSIZE) << 4;
399 	if (lios->c_cflag & LINUX_CSTOPB)
400 		bios->c_cflag |= CSTOPB;
401 	if (lios->c_cflag & LINUX_CREAD)
402 		bios->c_cflag |= CREAD;
403 	if (lios->c_cflag & LINUX_PARENB)
404 		bios->c_cflag |= PARENB;
405 	if (lios->c_cflag & LINUX_PARODD)
406 		bios->c_cflag |= PARODD;
407 	if (lios->c_cflag & LINUX_HUPCL)
408 		bios->c_cflag |= HUPCL;
409 	if (lios->c_cflag & LINUX_CLOCAL)
410 		bios->c_cflag |= CLOCAL;
411 	if (lios->c_cflag & LINUX_CRTSCTS)
412 		bios->c_cflag |= CRTSCTS;
413 
414 	bios->c_lflag = 0;
415 	if (lios->c_lflag & LINUX_ISIG)
416 		bios->c_lflag |= ISIG;
417 	if (lios->c_lflag & LINUX_ICANON)
418 		bios->c_lflag |= ICANON;
419 	if (lios->c_lflag & LINUX_ECHO)
420 		bios->c_lflag |= ECHO;
421 	if (lios->c_lflag & LINUX_ECHOE)
422 		bios->c_lflag |= ECHOE;
423 	if (lios->c_lflag & LINUX_ECHOK)
424 		bios->c_lflag |= ECHOK;
425 	if (lios->c_lflag & LINUX_ECHONL)
426 		bios->c_lflag |= ECHONL;
427 	if (lios->c_lflag & LINUX_NOFLSH)
428 		bios->c_lflag |= NOFLSH;
429 	if (lios->c_lflag & LINUX_TOSTOP)
430 		bios->c_lflag |= TOSTOP;
431 	if (lios->c_lflag & LINUX_ECHOCTL)
432 		bios->c_lflag |= ECHOCTL;
433 	if (lios->c_lflag & LINUX_ECHOPRT)
434 		bios->c_lflag |= ECHOPRT;
435 	if (lios->c_lflag & LINUX_ECHOKE)
436 		bios->c_lflag |= ECHOKE;
437 	if (lios->c_lflag & LINUX_FLUSHO)
438 		bios->c_lflag |= FLUSHO;
439 	if (lios->c_lflag & LINUX_PENDIN)
440 		bios->c_lflag |= PENDIN;
441 	if (lios->c_lflag & LINUX_IEXTEN)
442 		bios->c_lflag |= IEXTEN;
443 
444 	for (i=0; i<NCCS; i++)
445 		bios->c_cc[i] = _POSIX_VDISABLE;
446 	bios->c_cc[VINTR] = lios->c_cc[LINUX_VINTR];
447 	bios->c_cc[VQUIT] = lios->c_cc[LINUX_VQUIT];
448 	bios->c_cc[VERASE] = lios->c_cc[LINUX_VERASE];
449 	bios->c_cc[VKILL] = lios->c_cc[LINUX_VKILL];
450 	bios->c_cc[VEOF] = lios->c_cc[LINUX_VEOF];
451 	bios->c_cc[VEOL] = lios->c_cc[LINUX_VEOL];
452 	bios->c_cc[VMIN] = lios->c_cc[LINUX_VMIN];
453 	bios->c_cc[VTIME] = lios->c_cc[LINUX_VTIME];
454 	bios->c_cc[VEOL2] = lios->c_cc[LINUX_VEOL2];
455 	bios->c_cc[VSUSP] = lios->c_cc[LINUX_VSUSP];
456 	bios->c_cc[VSTART] = lios->c_cc[LINUX_VSTART];
457 	bios->c_cc[VSTOP] = lios->c_cc[LINUX_VSTOP];
458 	bios->c_cc[VREPRINT] = lios->c_cc[LINUX_VREPRINT];
459 	bios->c_cc[VDISCARD] = lios->c_cc[LINUX_VDISCARD];
460 	bios->c_cc[VWERASE] = lios->c_cc[LINUX_VWERASE];
461 	bios->c_cc[VLNEXT] = lios->c_cc[LINUX_VLNEXT];
462 
463 	for (i=0; i<NCCS; i++) {
464 		if (bios->c_cc[i] == LINUX_POSIX_VDISABLE)
465 			bios->c_cc[i] = _POSIX_VDISABLE;
466 	}
467 
468 	bios->c_ispeed = bios->c_ospeed =
469 	    linux_to_bsd_speed(lios->c_cflag & LINUX_CBAUD, sptab);
470 
471 #ifdef DEBUG
472 	if (ldebug(ioctl)) {
473 		printf("LINUX: BSD termios structure (output):\n");
474 		printf("i=%08x o=%08x c=%08x l=%08x ispeed=%d ospeed=%d\n",
475 		    bios->c_iflag, bios->c_oflag, bios->c_cflag, bios->c_lflag,
476 		    bios->c_ispeed, bios->c_ospeed);
477 		printf("c_cc ");
478 		for (i=0; i<NCCS; i++)
479 			printf("%02x ", bios->c_cc[i]);
480 		printf("\n");
481 	}
482 #endif
483 }
484 
485 static void
486 bsd_to_linux_termio(struct termios *bios, struct linux_termio *lio)
487 {
488 	struct linux_termios lios;
489 
490 	bsd_to_linux_termios(bios, &lios);
491 	lio->c_iflag = lios.c_iflag;
492 	lio->c_oflag = lios.c_oflag;
493 	lio->c_cflag = lios.c_cflag;
494 	lio->c_lflag = lios.c_lflag;
495 	lio->c_line  = lios.c_line;
496 #ifdef __alpha__
497 	lio->c_cc[LINUX__VINTR] = lios.c_cc[LINUX_VINTR];
498 	lio->c_cc[LINUX__VQUIT] = lios.c_cc[LINUX_VQUIT];
499 	lio->c_cc[LINUX__VERASE] = lios.c_cc[LINUX_VERASE];
500 	lio->c_cc[LINUX__VKILL] = lios.c_cc[LINUX_VKILL];
501 	lio->c_cc[LINUX__VEOF] =
502 	    lios.c_cc[(lios.c_lflag & ICANON) ? LINUX_VEOF : LINUX_VMIN];
503 	lio->c_cc[LINUX__VEOL] =
504 	    lios.c_cc[(lios.c_lflag & ICANON) ? LINUX_VEOL : LINUX_VTIME];
505 	lio->c_cc[LINUX__VEOL2] = lios.c_cc[LINUX_VEOL2];
506 	lio->c_cc[LINUX__VSWTC] = lios.c_cc[LINUX_VSWTC];
507 #else
508 	memcpy(lio->c_cc, lios.c_cc, LINUX_NCC);
509 #endif
510 }
511 
512 static void
513 linux_to_bsd_termio(struct linux_termio *lio, struct termios *bios)
514 {
515 	struct linux_termios lios;
516 	int i;
517 
518 	lios.c_iflag = lio->c_iflag;
519 	lios.c_oflag = lio->c_oflag;
520 	lios.c_cflag = lio->c_cflag;
521 	lios.c_lflag = lio->c_lflag;
522 #ifdef __alpha__
523 	for (i=0; i<LINUX_NCCS; i++)
524 		lios.c_cc[i] = LINUX_POSIX_VDISABLE;
525 	lios.c_cc[LINUX_VINTR] = lio->c_cc[LINUX__VINTR];
526 	lios.c_cc[LINUX_VQUIT] = lio->c_cc[LINUX__VQUIT];
527 	lios.c_cc[LINUX_VERASE] = lio->c_cc[LINUX__VERASE];
528 	lios.c_cc[LINUX_VKILL] = lio->c_cc[LINUX__VKILL];
529 	lios.c_cc[LINUX_VEOL2] = lio->c_cc[LINUX__VEOL2];
530 	lios.c_cc[LINUX_VSWTC] = lio->c_cc[LINUX__VSWTC];
531 	lios.c_cc[(lio->c_lflag & ICANON) ? LINUX_VEOF : LINUX_VMIN] =
532 	    lio->c_cc[LINUX__VEOF];
533 	lios.c_cc[(lio->c_lflag & ICANON) ? LINUX_VEOL : LINUX_VTIME] =
534 	    lio->c_cc[LINUX__VEOL];
535 #else
536 	for (i=LINUX_NCC; i<LINUX_NCCS; i++)
537 		lios.c_cc[i] = LINUX_POSIX_VDISABLE;
538 	memcpy(lios.c_cc, lio->c_cc, LINUX_NCC);
539 #endif
540 	linux_to_bsd_termios(&lios, bios);
541 }
542 
543 static int
544 linux_ioctl_termio(struct thread *td, struct linux_ioctl_args *args)
545 {
546 	struct termios bios;
547 	struct linux_termios lios;
548 	struct linux_termio lio;
549 	struct file *fp = td->td_proc->p_fd->fd_ofiles[args->fd];
550 	int error;
551 
552 	switch (args->cmd & 0xffff) {
553 
554 	case LINUX_TCGETS:
555 		error = fo_ioctl(fp, TIOCGETA, (caddr_t)&bios, td);
556 		if (error)
557 			return (error);
558 		bsd_to_linux_termios(&bios, &lios);
559 		return copyout(&lios, (caddr_t)args->arg, sizeof(lios));
560 
561 	case LINUX_TCSETS:
562 		error = copyin((caddr_t)args->arg, &lios, sizeof(lios));
563 		if (error)
564 			return (error);
565 		linux_to_bsd_termios(&lios, &bios);
566 		return (fo_ioctl(fp, TIOCSETA, (caddr_t)&bios, td));
567 
568 	case LINUX_TCSETSW:
569 		error = copyin((caddr_t)args->arg, &lios, sizeof(lios));
570 		if (error)
571 			return (error);
572 		linux_to_bsd_termios(&lios, &bios);
573 		return (fo_ioctl(fp, TIOCSETAW, (caddr_t)&bios, td));
574 
575 	case LINUX_TCSETSF:
576 		error = copyin((caddr_t)args->arg, &lios, sizeof(lios));
577 		if (error)
578 			return (error);
579 		linux_to_bsd_termios(&lios, &bios);
580 		return (fo_ioctl(fp, TIOCSETAF, (caddr_t)&bios, td));
581 
582 	case LINUX_TCGETA:
583 		error = fo_ioctl(fp, TIOCGETA, (caddr_t)&bios, td);
584 		if (error)
585 			return (error);
586 		bsd_to_linux_termio(&bios, &lio);
587 		return (copyout(&lio, (caddr_t)args->arg, sizeof(lio)));
588 
589 	case LINUX_TCSETA:
590 		error = copyin((caddr_t)args->arg, &lio, sizeof(lio));
591 		if (error)
592 			return (error);
593 		linux_to_bsd_termio(&lio, &bios);
594 		return (fo_ioctl(fp, TIOCSETA, (caddr_t)&bios, td));
595 
596 	case LINUX_TCSETAW:
597 		error = copyin((caddr_t)args->arg, &lio, sizeof(lio));
598 		if (error)
599 			return (error);
600 		linux_to_bsd_termio(&lio, &bios);
601 		return (fo_ioctl(fp, TIOCSETAW, (caddr_t)&bios, td));
602 
603 	case LINUX_TCSETAF:
604 		error = copyin((caddr_t)args->arg, &lio, sizeof(lio));
605 		if (error)
606 			return (error);
607 		linux_to_bsd_termio(&lio, &bios);
608 		return (fo_ioctl(fp, TIOCSETAF, (caddr_t)&bios, td));
609 
610 	/* LINUX_TCSBRK */
611 
612 	case LINUX_TCXONC: {
613 		switch (args->arg) {
614 		case LINUX_TCOOFF:
615 			args->cmd = TIOCSTOP;
616 			break;
617 		case LINUX_TCOON:
618 			args->cmd = TIOCSTART;
619 			break;
620 		case LINUX_TCIOFF:
621 		case LINUX_TCION: {
622 			int c;
623 			struct write_args wr;
624 			error = fo_ioctl(fp, TIOCGETA, (caddr_t)&bios, td);
625 			if (error)
626 				return (error);
627 			c = (args->arg == LINUX_TCIOFF) ? VSTOP : VSTART;
628 			c = bios.c_cc[c];
629 			if (c != _POSIX_VDISABLE) {
630 				wr.fd = args->fd;
631 				wr.buf = &c;
632 				wr.nbyte = sizeof(c);
633 				return (write(td, &wr));
634 			} else
635 				return (0);
636 		}
637 		default:
638 			return (EINVAL);
639 		}
640 		args->arg = 0;
641 		return (ioctl(td, (struct ioctl_args *)args));
642 	}
643 
644 	case LINUX_TCFLSH: {
645 		args->cmd = TIOCFLUSH;
646 		switch (args->arg) {
647 		case LINUX_TCIFLUSH:
648 			args->arg = FREAD;
649 			break;
650 		case LINUX_TCOFLUSH:
651 			args->arg = FWRITE;
652 			break;
653 		case LINUX_TCIOFLUSH:
654 			args->arg = FREAD | FWRITE;
655 			break;
656 		default:
657 			return (EINVAL);
658 		}
659 		return (ioctl(td, (struct ioctl_args *)args));
660 	}
661 
662 	case LINUX_TIOCEXCL:
663 		args->cmd = TIOCEXCL;
664 		return (ioctl(td, (struct ioctl_args *)args));
665 
666 	case LINUX_TIOCNXCL:
667 		args->cmd = TIOCNXCL;
668 		return (ioctl(td, (struct ioctl_args *)args));
669 
670 	/* LINUX_TIOCSCTTY */
671 
672 	case LINUX_TIOCGPGRP:
673 		args->cmd = TIOCGPGRP;
674 		return (ioctl(td, (struct ioctl_args *)args));
675 
676 	case LINUX_TIOCSPGRP:
677 		args->cmd = TIOCSPGRP;
678 		return (ioctl(td, (struct ioctl_args *)args));
679 
680 	/* LINUX_TIOCOUTQ */
681 	/* LINUX_TIOCSTI */
682 
683 	case LINUX_TIOCGWINSZ:
684 		args->cmd = TIOCGWINSZ;
685 		return (ioctl(td, (struct ioctl_args *)args));
686 
687 	case LINUX_TIOCSWINSZ:
688 		args->cmd = TIOCSWINSZ;
689 		return (ioctl(td, (struct ioctl_args *)args));
690 
691 	case LINUX_TIOCMGET:
692 		args->cmd = TIOCMGET;
693 		return (ioctl(td, (struct ioctl_args *)args));
694 
695 	case LINUX_TIOCMBIS:
696 		args->cmd = TIOCMBIS;
697 		return (ioctl(td, (struct ioctl_args *)args));
698 
699 	case LINUX_TIOCMBIC:
700 		args->cmd = TIOCMBIC;
701 		return (ioctl(td, (struct ioctl_args *)args));
702 
703 	case LINUX_TIOCMSET:
704 		args->cmd = TIOCMSET;
705 		return (ioctl(td, (struct ioctl_args *)args));
706 
707 	/* TIOCGSOFTCAR */
708 	/* TIOCSSOFTCAR */
709 
710 	case LINUX_FIONREAD: /* LINUX_TIOCINQ */
711 		args->cmd = FIONREAD;
712 		return (ioctl(td, (struct ioctl_args *)args));
713 
714 	/* LINUX_TIOCLINUX */
715 
716 	case LINUX_TIOCCONS:
717 		args->cmd = TIOCCONS;
718 		return (ioctl(td, (struct ioctl_args *)args));
719 
720 	case LINUX_TIOCGSERIAL: {
721 		struct linux_serial_struct lss;
722 		lss.type = LINUX_PORT_16550A;
723 		lss.flags = 0;
724 		lss.close_delay = 0;
725 		return copyout(&lss, (caddr_t)args->arg, sizeof(lss));
726 	}
727 
728 	case LINUX_TIOCSSERIAL: {
729 		struct linux_serial_struct lss;
730 		error = copyin((caddr_t)args->arg, &lss, sizeof(lss));
731 		if (error)
732 			return (error);
733 		/* XXX - It really helps to have an implementation that
734 		 * does nothing. NOT!
735 		 */
736 		return (0);
737 	}
738 
739 	/* LINUX_TIOCPKT */
740 
741 	case LINUX_FIONBIO:
742 		args->cmd = FIONBIO;
743 		return (ioctl(td, (struct ioctl_args *)args));
744 
745 	case LINUX_TIOCNOTTY:
746 		args->cmd = TIOCNOTTY;
747 		return (ioctl(td, (struct ioctl_args *)args));
748 
749 	case LINUX_TIOCSETD: {
750 		int line;
751 		switch (args->arg) {
752 		case LINUX_N_TTY:
753 			line = TTYDISC;
754 			break;
755 		case LINUX_N_SLIP:
756 			line = SLIPDISC;
757 			break;
758 		case LINUX_N_PPP:
759 			line = PPPDISC;
760 			break;
761 		default:
762 			return (EINVAL);
763 		}
764 		return (fo_ioctl(fp, TIOCSETD, (caddr_t)&line, td));
765 	}
766 
767 	case LINUX_TIOCGETD: {
768 		int linux_line;
769 		int bsd_line = TTYDISC;
770 		error = fo_ioctl(fp, TIOCGETD, (caddr_t)&bsd_line, td);
771 		if (error)
772 			return (error);
773 		switch (bsd_line) {
774 		case TTYDISC:
775 			linux_line = LINUX_N_TTY;
776 			break;
777 		case SLIPDISC:
778 			linux_line = LINUX_N_SLIP;
779 			break;
780 		case PPPDISC:
781 			linux_line = LINUX_N_PPP;
782 			break;
783 		default:
784 			return (EINVAL);
785 		}
786 		return (copyout(&linux_line, (caddr_t)args->arg, sizeof(int)));
787 	}
788 
789 	/* LINUX_TCSBRKP */
790 	/* LINUX_TIOCTTYGSTRUCT */
791 
792 	case LINUX_FIONCLEX:
793 		args->cmd = FIONCLEX;
794 		return (ioctl(td, (struct ioctl_args *)args));
795 
796 	case LINUX_FIOCLEX:
797 		args->cmd = FIOCLEX;
798 		return (ioctl(td, (struct ioctl_args *)args));
799 
800 	case LINUX_FIOASYNC:
801 		args->cmd = FIOASYNC;
802 		return (ioctl(td, (struct ioctl_args *)args));
803 
804 	/* LINUX_TIOCSERCONFIG */
805 	/* LINUX_TIOCSERGWILD */
806 	/* LINUX_TIOCSERSWILD */
807 	/* LINUX_TIOCGLCKTRMIOS */
808 	/* LINUX_TIOCSLCKTRMIOS */
809 
810 	}
811 
812 	return (ENOIOCTL);
813 }
814 
815 /*
816  * CDROM related ioctls
817  */
818 
819 struct linux_cdrom_msf
820 {
821 	u_char	cdmsf_min0;
822 	u_char	cdmsf_sec0;
823 	u_char	cdmsf_frame0;
824 	u_char	cdmsf_min1;
825 	u_char	cdmsf_sec1;
826 	u_char	cdmsf_frame1;
827 };
828 
829 struct linux_cdrom_tochdr
830 {
831 	u_char	cdth_trk0;
832 	u_char	cdth_trk1;
833 };
834 
835 union linux_cdrom_addr
836 {
837 	struct {
838 		u_char	minute;
839 		u_char	second;
840 		u_char	frame;
841 	} msf;
842 	int	lba;
843 };
844 
845 struct linux_cdrom_tocentry
846 {
847 	u_char	cdte_track;
848 	u_char	cdte_adr:4;
849 	u_char	cdte_ctrl:4;
850 	u_char	cdte_format;
851 	union linux_cdrom_addr cdte_addr;
852 	u_char	cdte_datamode;
853 };
854 
855 struct linux_cdrom_subchnl
856 {
857 	u_char	cdsc_format;
858 	u_char	cdsc_audiostatus;
859 	u_char	cdsc_adr:4;
860 	u_char	cdsc_ctrl:4;
861 	u_char	cdsc_trk;
862 	u_char	cdsc_ind;
863 	union linux_cdrom_addr cdsc_absaddr;
864 	union linux_cdrom_addr cdsc_reladdr;
865 };
866 
867 static void
868 bsd_to_linux_msf_lba(u_char af, union msf_lba *bp, union linux_cdrom_addr *lp)
869 {
870 	if (af == CD_LBA_FORMAT)
871 		lp->lba = bp->lba;
872 	else {
873 		lp->msf.minute = bp->msf.minute;
874 		lp->msf.second = bp->msf.second;
875 		lp->msf.frame = bp->msf.frame;
876 	}
877 }
878 
879 static void
880 set_linux_cdrom_addr(union linux_cdrom_addr *addr, int format, int lba)
881 {
882 	if (format == LINUX_CDROM_MSF) {
883 		addr->msf.frame = lba % 75;
884 		lba /= 75;
885 		lba += 2;
886 		addr->msf.second = lba % 60;
887 		addr->msf.minute = lba / 60;
888 	} else
889 		addr->lba = lba;
890 }
891 
892 static int
893 linux_ioctl_cdrom(struct thread *td, struct linux_ioctl_args *args)
894 {
895 	struct file *fp = td->td_proc->p_fd->fd_ofiles[args->fd];
896 	int error;
897 
898 	switch (args->cmd & 0xffff) {
899 
900 	case LINUX_CDROMPAUSE:
901 		args->cmd = CDIOCPAUSE;
902 		return (ioctl(td, (struct ioctl_args *)args));
903 
904 	case LINUX_CDROMRESUME:
905 		args->cmd = CDIOCRESUME;
906 		return (ioctl(td, (struct ioctl_args *)args));
907 
908 	case LINUX_CDROMPLAYMSF:
909 		args->cmd = CDIOCPLAYMSF;
910 		return (ioctl(td, (struct ioctl_args *)args));
911 
912 	case LINUX_CDROMPLAYTRKIND:
913 		args->cmd = CDIOCPLAYTRACKS;
914 		return (ioctl(td, (struct ioctl_args *)args));
915 
916 	case LINUX_CDROMREADTOCHDR: {
917 		struct ioc_toc_header th;
918 		struct linux_cdrom_tochdr lth;
919 		error = fo_ioctl(fp, CDIOREADTOCHEADER, (caddr_t)&th, td);
920 		if (!error) {
921 			lth.cdth_trk0 = th.starting_track;
922 			lth.cdth_trk1 = th.ending_track;
923 			copyout(&lth, (caddr_t)args->arg, sizeof(lth));
924 		}
925 		return (error);
926 	}
927 
928 	case LINUX_CDROMREADTOCENTRY: {
929 		struct linux_cdrom_tocentry lte, *ltep =
930 		    (struct linux_cdrom_tocentry *)args->arg;
931 		struct ioc_read_toc_single_entry irtse;
932 		irtse.address_format = ltep->cdte_format;
933 		irtse.track = ltep->cdte_track;
934 		error = fo_ioctl(fp, CDIOREADTOCENTRY, (caddr_t)&irtse, td);
935 		if (!error) {
936 			lte = *ltep;
937 			lte.cdte_ctrl = irtse.entry.control;
938 			lte.cdte_adr = irtse.entry.addr_type;
939 			bsd_to_linux_msf_lba(irtse.address_format,
940 			    &irtse.entry.addr, &lte.cdte_addr);
941 			copyout(&lte, (caddr_t)args->arg, sizeof(lte));
942 		}
943 		return (error);
944 	}
945 
946 	case LINUX_CDROMSTOP:
947 		args->cmd = CDIOCSTOP;
948 		return (ioctl(td, (struct ioctl_args *)args));
949 
950 	case LINUX_CDROMSTART:
951 		args->cmd = CDIOCSTART;
952 		return (ioctl(td, (struct ioctl_args *)args));
953 
954 	case LINUX_CDROMEJECT:
955 		args->cmd = CDIOCEJECT;
956 		return (ioctl(td, (struct ioctl_args *)args));
957 
958 	/* LINUX_CDROMVOLCTRL */
959 
960 	case LINUX_CDROMSUBCHNL: {
961 		struct linux_cdrom_subchnl sc;
962 		struct ioc_read_subchannel bsdsc;
963 		struct cd_sub_channel_info *bsdinfo;
964 		caddr_t sg = stackgap_init();
965 		bsdinfo = (struct cd_sub_channel_info*)stackgap_alloc(&sg,
966 		    sizeof(struct cd_sub_channel_info));
967 		bsdsc.address_format = CD_LBA_FORMAT;
968 		bsdsc.data_format = CD_CURRENT_POSITION;
969 		bsdsc.track = 0;
970 		bsdsc.data_len = sizeof(struct cd_sub_channel_info);
971 		bsdsc.data = bsdinfo;
972 		error = fo_ioctl(fp, CDIOCREADSUBCHANNEL, (caddr_t)&bsdsc, td);
973 		if (error)
974 			return (error);
975 		error = copyin((caddr_t)args->arg, &sc,
976 		    sizeof(struct linux_cdrom_subchnl));
977 		if (error)
978 			return (error);
979 		sc.cdsc_audiostatus = bsdinfo->header.audio_status;
980 		sc.cdsc_adr = bsdinfo->what.position.addr_type;
981 		sc.cdsc_ctrl = bsdinfo->what.position.control;
982 		sc.cdsc_trk = bsdinfo->what.position.track_number;
983 		sc.cdsc_ind = bsdinfo->what.position.index_number;
984 		set_linux_cdrom_addr(&sc.cdsc_absaddr, sc.cdsc_format,
985 		    bsdinfo->what.position.absaddr.lba);
986 		set_linux_cdrom_addr(&sc.cdsc_reladdr, sc.cdsc_format,
987 		    bsdinfo->what.position.reladdr.lba);
988 		error = copyout(&sc, (caddr_t)args->arg,
989 		    sizeof(struct linux_cdrom_subchnl));
990 		return (error);
991 	}
992 
993 	/* LINUX_CDROMREADMODE2 */
994 	/* LINUX_CDROMREADMODE1 */
995 	/* LINUX_CDROMREADAUDIO */
996 	/* LINUX_CDROMEJECT_SW */
997 	/* LINUX_CDROMMULTISESSION */
998 	/* LINUX_CDROM_GET_UPC */
999 
1000 	case LINUX_CDROMRESET:
1001 		args->cmd = CDIOCRESET;
1002 		return (ioctl(td, (struct ioctl_args *)args));
1003 
1004 	/* LINUX_CDROMVOLREAD */
1005 	/* LINUX_CDROMREADRAW */
1006 	/* LINUX_CDROMREADCOOKED */
1007 	/* LINUX_CDROMSEEK */
1008 	/* LINUX_CDROMPLAYBLK */
1009 	/* LINUX_CDROMREADALL */
1010 	/* LINUX_CDROMCLOSETRAY */
1011 	/* LINUX_CDROMLOADFROMSLOT */
1012 
1013 	}
1014 
1015 	return (ENOIOCTL);
1016 }
1017 
1018 /*
1019  * Sound related ioctls
1020  */
1021 
1022 static u_int32_t dirbits[4] = { IOC_VOID, IOC_IN, IOC_OUT, IOC_INOUT };
1023 
1024 #define	SETDIR(c)	(((c) & ~IOC_DIRMASK) | dirbits[args->cmd >> 30])
1025 
1026 static int
1027 linux_ioctl_sound(struct thread *td, struct linux_ioctl_args *args)
1028 {
1029 
1030 	switch (args->cmd & 0xffff) {
1031 
1032 	case LINUX_SOUND_MIXER_WRITE_VOLUME:
1033 		args->cmd = SETDIR(SOUND_MIXER_WRITE_VOLUME);
1034 		return (ioctl(td, (struct ioctl_args *)args));
1035 
1036 	case LINUX_SOUND_MIXER_WRITE_BASS:
1037 		args->cmd = SETDIR(SOUND_MIXER_WRITE_BASS);
1038 		return (ioctl(td, (struct ioctl_args *)args));
1039 
1040 	case LINUX_SOUND_MIXER_WRITE_TREBLE:
1041 		args->cmd = SETDIR(SOUND_MIXER_WRITE_TREBLE);
1042 		return (ioctl(td, (struct ioctl_args *)args));
1043 
1044 	case LINUX_SOUND_MIXER_WRITE_SYNTH:
1045 		args->cmd = SETDIR(SOUND_MIXER_WRITE_SYNTH);
1046 		return (ioctl(td, (struct ioctl_args *)args));
1047 
1048 	case LINUX_SOUND_MIXER_WRITE_PCM:
1049 		args->cmd = SETDIR(SOUND_MIXER_WRITE_PCM);
1050 		return (ioctl(td, (struct ioctl_args *)args));
1051 
1052 	case LINUX_SOUND_MIXER_WRITE_SPEAKER:
1053 		args->cmd = SETDIR(SOUND_MIXER_WRITE_SPEAKER);
1054 		return (ioctl(td, (struct ioctl_args *)args));
1055 
1056 	case LINUX_SOUND_MIXER_WRITE_LINE:
1057 		args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE);
1058 		return (ioctl(td, (struct ioctl_args *)args));
1059 
1060 	case LINUX_SOUND_MIXER_WRITE_MIC:
1061 		args->cmd = SETDIR(SOUND_MIXER_WRITE_MIC);
1062 		return (ioctl(td, (struct ioctl_args *)args));
1063 
1064 	case LINUX_SOUND_MIXER_WRITE_CD:
1065 		args->cmd = SETDIR(SOUND_MIXER_WRITE_CD);
1066 		return (ioctl(td, (struct ioctl_args *)args));
1067 
1068 	case LINUX_SOUND_MIXER_WRITE_IMIX:
1069 		args->cmd = SETDIR(SOUND_MIXER_WRITE_IMIX);
1070 		return (ioctl(td, (struct ioctl_args *)args));
1071 
1072 	case LINUX_SOUND_MIXER_WRITE_ALTPCM:
1073 		args->cmd = SETDIR(SOUND_MIXER_WRITE_ALTPCM);
1074 		return (ioctl(td, (struct ioctl_args *)args));
1075 
1076 	case LINUX_SOUND_MIXER_WRITE_RECLEV:
1077 		args->cmd = SETDIR(SOUND_MIXER_WRITE_RECLEV);
1078 		return (ioctl(td, (struct ioctl_args *)args));
1079 
1080 	case LINUX_SOUND_MIXER_WRITE_IGAIN:
1081 		args->cmd = SETDIR(SOUND_MIXER_WRITE_IGAIN);
1082 		return (ioctl(td, (struct ioctl_args *)args));
1083 
1084 	case LINUX_SOUND_MIXER_WRITE_OGAIN:
1085 		args->cmd = SETDIR(SOUND_MIXER_WRITE_OGAIN);
1086 		return (ioctl(td, (struct ioctl_args *)args));
1087 
1088 	case LINUX_SOUND_MIXER_WRITE_LINE1:
1089 		args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE1);
1090 		return (ioctl(td, (struct ioctl_args *)args));
1091 
1092 	case LINUX_SOUND_MIXER_WRITE_LINE2:
1093 		args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE2);
1094 		return (ioctl(td, (struct ioctl_args *)args));
1095 
1096 	case LINUX_SOUND_MIXER_WRITE_LINE3:
1097 		args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE3);
1098 		return (ioctl(td, (struct ioctl_args *)args));
1099 
1100 	case LINUX_OSS_GETVERSION: {
1101 		int version = linux_get_oss_version(td->td_proc);
1102 		return (copyout(&version, (caddr_t)args->arg, sizeof(int)));
1103 	}
1104 
1105 	case LINUX_SOUND_MIXER_READ_DEVMASK:
1106 		args->cmd = SOUND_MIXER_READ_DEVMASK;
1107 		return (ioctl(td, (struct ioctl_args *)args));
1108 
1109 	case LINUX_SNDCTL_DSP_RESET:
1110 		args->cmd = SNDCTL_DSP_RESET;
1111 		return (ioctl(td, (struct ioctl_args *)args));
1112 
1113 	case LINUX_SNDCTL_DSP_SYNC:
1114 		args->cmd = SNDCTL_DSP_SYNC;
1115 		return (ioctl(td, (struct ioctl_args *)args));
1116 
1117 	case LINUX_SNDCTL_DSP_SPEED:
1118 		args->cmd = SNDCTL_DSP_SPEED;
1119 		return (ioctl(td, (struct ioctl_args *)args));
1120 
1121 	case LINUX_SNDCTL_DSP_STEREO:
1122 		args->cmd = SNDCTL_DSP_STEREO;
1123 		return (ioctl(td, (struct ioctl_args *)args));
1124 
1125 	case LINUX_SNDCTL_DSP_GETBLKSIZE: /* LINUX_SNDCTL_DSP_SETBLKSIZE */
1126 		args->cmd = SNDCTL_DSP_GETBLKSIZE;
1127 		return (ioctl(td, (struct ioctl_args *)args));
1128 
1129 	case LINUX_SNDCTL_DSP_SETFMT:
1130 		args->cmd = SNDCTL_DSP_SETFMT;
1131 		return (ioctl(td, (struct ioctl_args *)args));
1132 
1133 	case LINUX_SOUND_PCM_WRITE_CHANNELS:
1134 		args->cmd = SOUND_PCM_WRITE_CHANNELS;
1135 		return (ioctl(td, (struct ioctl_args *)args));
1136 
1137 	case LINUX_SOUND_PCM_WRITE_FILTER:
1138 		args->cmd = SOUND_PCM_WRITE_FILTER;
1139 		return (ioctl(td, (struct ioctl_args *)args));
1140 
1141 	case LINUX_SNDCTL_DSP_POST:
1142 		args->cmd = SNDCTL_DSP_POST;
1143 		return (ioctl(td, (struct ioctl_args *)args));
1144 
1145 	case LINUX_SNDCTL_DSP_SUBDIVIDE:
1146 		args->cmd = SNDCTL_DSP_SUBDIVIDE;
1147 		return (ioctl(td, (struct ioctl_args *)args));
1148 
1149 	case LINUX_SNDCTL_DSP_SETFRAGMENT:
1150 		args->cmd = SNDCTL_DSP_SETFRAGMENT;
1151 		return (ioctl(td, (struct ioctl_args *)args));
1152 
1153 	case LINUX_SNDCTL_DSP_GETFMTS:
1154 		args->cmd = SNDCTL_DSP_GETFMTS;
1155 		return (ioctl(td, (struct ioctl_args *)args));
1156 
1157 	case LINUX_SNDCTL_DSP_GETOSPACE:
1158 		args->cmd = SNDCTL_DSP_GETOSPACE;
1159 		return (ioctl(td, (struct ioctl_args *)args));
1160 
1161 	case LINUX_SNDCTL_DSP_GETISPACE:
1162 		args->cmd = SNDCTL_DSP_GETISPACE;
1163 		return (ioctl(td, (struct ioctl_args *)args));
1164 
1165 	case LINUX_SNDCTL_DSP_NONBLOCK:
1166 		args->cmd = SNDCTL_DSP_NONBLOCK;
1167 		return (ioctl(td, (struct ioctl_args *)args));
1168 
1169 	case LINUX_SNDCTL_DSP_GETCAPS:
1170 		args->cmd = SNDCTL_DSP_GETCAPS;
1171 		return (ioctl(td, (struct ioctl_args *)args));
1172 
1173 	case LINUX_SNDCTL_DSP_SETTRIGGER: /* LINUX_SNDCTL_GETTRIGGER */
1174 		args->cmd = SNDCTL_DSP_SETTRIGGER;
1175 		return (ioctl(td, (struct ioctl_args *)args));
1176 
1177 	case LINUX_SNDCTL_DSP_GETIPTR:
1178 		args->cmd = SNDCTL_DSP_GETIPTR;
1179 		return (ioctl(td, (struct ioctl_args *)args));
1180 
1181 	case LINUX_SNDCTL_DSP_GETOPTR:
1182 		args->cmd = SNDCTL_DSP_GETOPTR;
1183 		return (ioctl(td, (struct ioctl_args *)args));
1184 
1185 	case LINUX_SNDCTL_DSP_GETODELAY:
1186 		args->cmd = SNDCTL_DSP_GETODELAY;
1187 		return (ioctl(td, (struct ioctl_args *)args));
1188 
1189 	case LINUX_SNDCTL_SEQ_RESET:
1190 		args->cmd = SNDCTL_SEQ_RESET;
1191 		return (ioctl(td, (struct ioctl_args *)args));
1192 
1193 	case LINUX_SNDCTL_SEQ_SYNC:
1194 		args->cmd = SNDCTL_SEQ_SYNC;
1195 		return (ioctl(td, (struct ioctl_args *)args));
1196 
1197 	case LINUX_SNDCTL_SYNTH_INFO:
1198 		args->cmd = SNDCTL_SYNTH_INFO;
1199 		return (ioctl(td, (struct ioctl_args *)args));
1200 
1201 	case LINUX_SNDCTL_SEQ_CTRLRATE:
1202 		args->cmd = SNDCTL_SEQ_CTRLRATE;
1203 		return (ioctl(td, (struct ioctl_args *)args));
1204 
1205 	case LINUX_SNDCTL_SEQ_GETOUTCOUNT:
1206 		args->cmd = SNDCTL_SEQ_GETOUTCOUNT;
1207 		return (ioctl(td, (struct ioctl_args *)args));
1208 
1209 	case LINUX_SNDCTL_SEQ_GETINCOUNT:
1210 		args->cmd = SNDCTL_SEQ_GETINCOUNT;
1211 		return (ioctl(td, (struct ioctl_args *)args));
1212 
1213 	case LINUX_SNDCTL_SEQ_PERCMODE:
1214 		args->cmd = SNDCTL_SEQ_PERCMODE;
1215 		return (ioctl(td, (struct ioctl_args *)args));
1216 
1217 	case LINUX_SNDCTL_FM_LOAD_INSTR:
1218 		args->cmd = SNDCTL_FM_LOAD_INSTR;
1219 		return (ioctl(td, (struct ioctl_args *)args));
1220 
1221 	case LINUX_SNDCTL_SEQ_TESTMIDI:
1222 		args->cmd = SNDCTL_SEQ_TESTMIDI;
1223 		return (ioctl(td, (struct ioctl_args *)args));
1224 
1225 	case LINUX_SNDCTL_SEQ_RESETSAMPLES:
1226 		args->cmd = SNDCTL_SEQ_RESETSAMPLES;
1227 		return (ioctl(td, (struct ioctl_args *)args));
1228 
1229 	case LINUX_SNDCTL_SEQ_NRSYNTHS:
1230 		args->cmd = SNDCTL_SEQ_NRSYNTHS;
1231 		return (ioctl(td, (struct ioctl_args *)args));
1232 
1233 	case LINUX_SNDCTL_SEQ_NRMIDIS:
1234 		args->cmd = SNDCTL_SEQ_NRMIDIS;
1235 		return (ioctl(td, (struct ioctl_args *)args));
1236 
1237 	case LINUX_SNDCTL_MIDI_INFO:
1238 		args->cmd = SNDCTL_MIDI_INFO;
1239 		return (ioctl(td, (struct ioctl_args *)args));
1240 
1241 	case LINUX_SNDCTL_SEQ_TRESHOLD:
1242 		args->cmd = SNDCTL_SEQ_TRESHOLD;
1243 		return (ioctl(td, (struct ioctl_args *)args));
1244 
1245 	case LINUX_SNDCTL_SYNTH_MEMAVL:
1246 		args->cmd = SNDCTL_SYNTH_MEMAVL;
1247 		return (ioctl(td, (struct ioctl_args *)args));
1248 
1249 	}
1250 
1251 	return (ENOIOCTL);
1252 }
1253 
1254 /*
1255  * Console related ioctls
1256  */
1257 
1258 #define ISSIGVALID(sig)		((sig) > 0 && (sig) < NSIG)
1259 
1260 static int
1261 linux_ioctl_console(struct thread *td, struct linux_ioctl_args *args)
1262 {
1263 	struct file *fp = td->td_proc->p_fd->fd_ofiles[args->fd];
1264 
1265 	switch (args->cmd & 0xffff) {
1266 
1267 	case LINUX_KIOCSOUND:
1268 		args->cmd = KIOCSOUND;
1269 		return (ioctl(td, (struct ioctl_args *)args));
1270 
1271 	case LINUX_KDMKTONE:
1272 		args->cmd = KDMKTONE;
1273 		return (ioctl(td, (struct ioctl_args *)args));
1274 
1275 	case LINUX_KDGETLED:
1276 		args->cmd = KDGETLED;
1277 		return (ioctl(td, (struct ioctl_args *)args));
1278 
1279 	case LINUX_KDSETLED:
1280 		args->cmd = KDSETLED;
1281 		return (ioctl(td, (struct ioctl_args *)args));
1282 
1283 	case LINUX_KDSETMODE:
1284 		args->cmd = KDSETMODE;
1285 		return (ioctl(td, (struct ioctl_args *)args));
1286 
1287 	case LINUX_KDGETMODE:
1288 		args->cmd = KDGETMODE;
1289 		return (ioctl(td, (struct ioctl_args *)args));
1290 
1291 	case LINUX_KDGKBMODE:
1292 		args->cmd = KDGKBMODE;
1293 		return (ioctl(td, (struct ioctl_args *)args));
1294 
1295 	case LINUX_KDSKBMODE: {
1296 		int kbdmode;
1297 		switch (args->arg) {
1298 		case LINUX_KBD_RAW:
1299 			kbdmode = K_RAW;
1300 			break;
1301 		case LINUX_KBD_XLATE:
1302 			kbdmode = K_XLATE;
1303 			break;
1304 		case LINUX_KBD_MEDIUMRAW:
1305 			kbdmode = K_RAW;
1306 			break;
1307 		default:
1308 			return (EINVAL);
1309 		}
1310 		return (fo_ioctl(fp, KDSKBMODE, (caddr_t)&kbdmode, td));
1311 	}
1312 
1313 	case LINUX_VT_OPENQRY:
1314 		args->cmd = VT_OPENQRY;
1315 		return (ioctl(td, (struct ioctl_args *)args));
1316 
1317 	case LINUX_VT_GETMODE:
1318 		args->cmd = VT_GETMODE;
1319 		return  (ioctl(td, (struct ioctl_args *)args));
1320 
1321 	case LINUX_VT_SETMODE: {
1322 		struct vt_mode *mode;
1323 		args->cmd = VT_SETMODE;
1324 		mode = (struct vt_mode *)args->arg;
1325 		if (!ISSIGVALID(mode->frsig) && ISSIGVALID(mode->acqsig))
1326 			mode->frsig = mode->acqsig;
1327 		return (ioctl(td, (struct ioctl_args *)args));
1328 	}
1329 
1330 	case LINUX_VT_GETSTATE:
1331 		args->cmd = VT_GETACTIVE;
1332 		return (ioctl(td, (struct ioctl_args *)args));
1333 
1334 	case LINUX_VT_RELDISP:
1335 		args->cmd = VT_RELDISP;
1336 		return (ioctl(td, (struct ioctl_args *)args));
1337 
1338 	case LINUX_VT_ACTIVATE:
1339 		args->cmd = VT_ACTIVATE;
1340 		return (ioctl(td, (struct ioctl_args *)args));
1341 
1342 	case LINUX_VT_WAITACTIVE:
1343 		args->cmd = VT_WAITACTIVE;
1344 		return (ioctl(td, (struct ioctl_args *)args));
1345 
1346 	}
1347 
1348 	return (ENOIOCTL);
1349 }
1350 
1351 #define IFP_IS_ETH(ifp) ((ifp->if_flags & \
1352 	(IFF_LOOPBACK|IFF_POINTOPOINT|IFF_BROADCAST)) == \
1353 	IFF_BROADCAST)
1354 
1355 /*
1356  * Construct the Linux name for an interface
1357  */
1358 
1359 int
1360 linux_ifname(struct ifnet *ifp, char *name, size_t size)
1361 {
1362 	if (IFP_IS_ETH(ifp))
1363 		return snprintf(name, LINUX_IFNAMSIZ,
1364 		    "eth%d", ifp->if_index);
1365 	return snprintf(name, LINUX_IFNAMSIZ,
1366 	    "%s%d", ifp->if_name, ifp->if_unit);
1367 }
1368 
1369 /*
1370  * Translate a FreeBSD interface name to a Linux interface name,
1371  * and return the associated ifnet structure.
1372  * bsdname and lxname need to be least IFNAMSIZ bytes long, but
1373  * can point to the same buffer.
1374  */
1375 
1376 static struct ifnet *
1377 ifname_bsd_to_linux(const char *bsdname, char *lxname)
1378 {
1379 	struct ifnet *ifp;
1380 	int len, unit;
1381 	char *ep;
1382 
1383 	for (len = 0; len < IFNAMSIZ; ++len)
1384 		if (!isalpha(bsdname[len]))
1385 			break;
1386 	if (len == 0 || len == IFNAMSIZ)
1387 		return (NULL);
1388 	unit = (int)strtoul(bsdname + len, &ep, 10);
1389 	if (ep == NULL || ep == bsdname + len || ep >= bsdname + IFNAMSIZ)
1390 		return (NULL);
1391 	TAILQ_FOREACH(ifp, &ifnet, if_link) {
1392 		if (ifp->if_unit == unit && ifp->if_name[len] == '\0' &&
1393 		    strncmp(ifp->if_name, bsdname, len) == 0)
1394 			break;
1395 	}
1396 	if (ifp != NULL)
1397 		linux_ifname(ifp, lxname, LINUX_IFNAMSIZ);
1398 
1399 	return (ifp);
1400 }
1401 
1402 /*
1403  * Translate a Linux interface name to a FreeBSD interface name,
1404  * and return the associated ifnet structure
1405  * bsdname and lxname need to be least IFNAMSIZ bytes long, but
1406  * can point to the same buffer.
1407  */
1408 
1409 static struct ifnet *
1410 ifname_linux_to_bsd(const char *lxname, char *bsdname)
1411 {
1412 	struct ifnet *ifp;
1413 	int len, unit;
1414 	char *ep;
1415 
1416 	for (len = 0; len < LINUX_IFNAMSIZ; ++len)
1417 		if (!isalpha(lxname[len]))
1418 			break;
1419 	if (len == 0 || len == LINUX_IFNAMSIZ)
1420 		return (NULL);
1421 	unit = (int)strtoul(lxname + len, &ep, 10);
1422 	if (ep == NULL || ep == lxname + len || ep >= lxname + LINUX_IFNAMSIZ)
1423 		return (NULL);
1424 	TAILQ_FOREACH(ifp, &ifnet, if_link) {
1425 		/* allow Linux programs to use FreeBSD names */
1426 		if (ifp->if_unit == unit && ifp->if_name[len] == '\0' &&
1427 		    strncmp(ifp->if_name, lxname, len) == 0)
1428 			break;
1429 		if (ifp->if_index == unit && IFP_IS_ETH(ifp) &&
1430 		    strncmp(lxname, "eth", len) == 0)
1431 			break;
1432 	}
1433 	if (ifp != NULL)
1434 		snprintf(bsdname, IFNAMSIZ, "%s%d", ifp->if_name, ifp->if_unit);
1435 	return (ifp);
1436 }
1437 
1438 /*
1439  * Implement the SIOCGIFCONF ioctl
1440  */
1441 
1442 static int
1443 linux_ifconf(struct thread *td, struct ifconf *uifc)
1444 {
1445 	struct ifconf ifc;
1446 	struct l_ifreq ifr;
1447 	struct ifnet *ifp;
1448 	struct iovec iov;
1449 	struct uio uio;
1450 	int error;
1451 
1452 	error = copyin(uifc, &ifc, sizeof ifc);
1453 	if (error != 0)
1454 		return (error);
1455 
1456 	/* much easier to use uiomove than keep track ourselves */
1457 	iov.iov_base = ifc.ifc_buf;
1458 	iov.iov_len = ifc.ifc_len;
1459 	uio.uio_iov = &iov;
1460 	uio.uio_iovcnt = 1;
1461 	uio.uio_offset = 0;
1462 	uio.uio_resid = ifc.ifc_len;
1463 	uio.uio_segflg = UIO_USERSPACE;
1464 	uio.uio_rw = UIO_READ;
1465 	uio.uio_td = td;
1466 
1467 	/* return interface names but no addresses. */
1468 	TAILQ_FOREACH(ifp, &ifnet, if_link) {
1469 		if (uio.uio_resid <= 0)
1470 			break;
1471 		bzero(&ifr, sizeof ifr);
1472 		linux_ifname(ifp, ifr.ifr_name, LINUX_IFNAMSIZ);
1473 		error = uiomove((caddr_t)&ifr, sizeof ifr, &uio);
1474 		if (error != 0)
1475 			return (error);
1476 	}
1477 
1478 	ifc.ifc_len -= uio.uio_resid;
1479 	error = copyout(&ifc, uifc, sizeof ifc);
1480 
1481 	return (error);
1482 }
1483 
1484 static int
1485 linux_gifflags(struct thread *td, struct ifnet *ifp, struct l_ifreq *ifr)
1486 {
1487 	l_short flags;
1488 
1489 	flags = ifp->if_flags;
1490 	/* these flags have no Linux equivalent */
1491 	flags &= ~(IFF_SMART|IFF_OACTIVE|IFF_SIMPLEX|
1492 	    IFF_LINK0|IFF_LINK1|IFF_LINK2);
1493 	/* Linux' multicast flag is in a different bit */
1494 	if (flags & IFF_MULTICAST) {
1495 		flags &= ~IFF_MULTICAST;
1496 		flags |= 0x1000;
1497 	}
1498 
1499 	return (copyout(&flags, &ifr->ifr_flags, sizeof flags));
1500 }
1501 
1502 #define ARPHRD_ETHER	1
1503 #define ARPHRD_LOOPBACK	772
1504 
1505 static int
1506 linux_gifhwaddr(struct ifnet *ifp, struct l_ifreq *ifr)
1507 {
1508 	struct ifaddr *ifa;
1509 	struct sockaddr_dl *sdl;
1510 	struct l_sockaddr lsa;
1511 
1512 	if (ifp->if_type == IFT_LOOP) {
1513 		bzero(&lsa, sizeof lsa);
1514 		lsa.sa_family = ARPHRD_LOOPBACK;
1515 		return (copyout(&lsa, &ifr->ifr_hwaddr, sizeof lsa));
1516 	}
1517 
1518 	if (ifp->if_type != IFT_ETHER)
1519 		return (ENOENT);
1520 
1521 	TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
1522 		sdl = (struct sockaddr_dl*)ifa->ifa_addr;
1523 		if (sdl != NULL && (sdl->sdl_family == AF_LINK) &&
1524 		    (sdl->sdl_type == IFT_ETHER)) {
1525 			bzero(&lsa, sizeof lsa);
1526 			lsa.sa_family = ARPHRD_ETHER;
1527 			bcopy(LLADDR(sdl), lsa.sa_data, LINUX_IFHWADDRLEN);
1528 			return (copyout(&lsa, &ifr->ifr_hwaddr, sizeof lsa));
1529 		}
1530 	}
1531 
1532 	return (ENOENT);
1533 }
1534 
1535 /*
1536  * Socket related ioctls
1537  */
1538 
1539 static int
1540 linux_ioctl_socket(struct thread *td, struct linux_ioctl_args *args)
1541 {
1542 	char lifname[LINUX_IFNAMSIZ], ifname[IFNAMSIZ];
1543 	struct ifnet *ifp;
1544 	int error;
1545 
1546 	KASSERT(LINUX_IFNAMSIZ == IFNAMSIZ,
1547 	    (__FUNCTION__ "(): LINUX_IFNAMSIZ != IFNAMSIZ"));
1548 
1549 	ifp = NULL;
1550 	error = 0;
1551 
1552 	switch (args->cmd & 0xffff) {
1553 
1554 	case LINUX_FIOGETOWN:
1555 	case LINUX_FIOSETOWN:
1556 	case LINUX_SIOCADDMULTI:
1557 	case LINUX_SIOCATMARK:
1558 	case LINUX_SIOCDELMULTI:
1559 	case LINUX_SIOCGIFCONF:
1560 	case LINUX_SIOCGPGRP:
1561 	case LINUX_SIOCSPGRP:
1562 		/* these ioctls don't take an interface name */
1563 #ifdef DEBUG
1564 		printf(__FUNCTION__ "(): ioctl %d\n",
1565 		    args->cmd & 0xffff);
1566 #endif
1567 		break;
1568 
1569 	case LINUX_SIOCGIFFLAGS:
1570 	case LINUX_SIOCGIFADDR:
1571 	case LINUX_SIOCGIFDSTADDR:
1572 	case LINUX_SIOCGIFBRDADDR:
1573 	case LINUX_SIOCGIFNETMASK:
1574 	case LINUX_SIOCSIFNETMASK:
1575 	case LINUX_SIOCGIFMTU:
1576 	case LINUX_SIOCSIFMTU:
1577 	case LINUX_SIOCSIFNAME:
1578 	case LINUX_SIOCGIFHWADDR:
1579 	case LINUX_SIOCSIFHWADDR:
1580 	case LINUX_SIOCDEVPRIVATE:
1581 	case LINUX_SIOCDEVPRIVATE+1:
1582 		/* copy in the interface name and translate it. */
1583 		error = copyin((char *)args->arg, lifname, LINUX_IFNAMSIZ);
1584 		if (error != 0)
1585 			return (error);
1586 #ifdef DEBUG
1587 		printf(__FUNCTION__ "(): ioctl %d on %.*s\n",
1588 		    args->cmd & 0xffff, LINUX_IFNAMSIZ, lifname);
1589 #endif
1590 		ifp = ifname_linux_to_bsd(lifname, ifname);
1591 		if (ifp == NULL)
1592 			return (EINVAL);
1593 		/*
1594 		 * We need to copy it back out in case we pass the
1595 		 * request on to our native ioctl(), which will expect
1596 		 * the ifreq to be in user space and have the correct
1597 		 * interface name.
1598 		 */
1599 		error = copyout(ifname, (char *)args->arg, IFNAMSIZ);
1600 		if (error != 0)
1601 			return (error);
1602 #ifdef DEBUG
1603 		printf(__FUNCTION__ "(): %s translated to %s\n",
1604 		    lifname, ifname);
1605 #endif
1606 		break;
1607 
1608 	default:
1609 		return (ENOIOCTL);
1610 	}
1611 
1612 	switch (args->cmd & 0xffff) {
1613 
1614 	case LINUX_FIOSETOWN:
1615 		args->cmd = FIOSETOWN;
1616 		error = ioctl(td, (struct ioctl_args *)args);
1617 		break;
1618 
1619 	case LINUX_SIOCSPGRP:
1620 		args->cmd = SIOCSPGRP;
1621 		error = ioctl(td, (struct ioctl_args *)args);
1622 		break;
1623 
1624 	case LINUX_FIOGETOWN:
1625 		args->cmd = FIOGETOWN;
1626 		error = ioctl(td, (struct ioctl_args *)args);
1627 		break;
1628 
1629 	case LINUX_SIOCGPGRP:
1630 		args->cmd = SIOCGPGRP;
1631 		error = ioctl(td, (struct ioctl_args *)args);
1632 		break;
1633 
1634 	case LINUX_SIOCATMARK:
1635 		args->cmd = SIOCATMARK;
1636 		error = ioctl(td, (struct ioctl_args *)args);
1637 		break;
1638 
1639 	/* LINUX_SIOCGSTAMP */
1640 
1641 	case LINUX_SIOCGIFCONF:
1642 		error = linux_ifconf(td, (struct ifconf *)args->arg);
1643 		break;
1644 
1645 	case LINUX_SIOCGIFFLAGS:
1646 		args->cmd = SIOCGIFFLAGS;
1647 		error = linux_gifflags(td, ifp, (struct l_ifreq *)args->arg);
1648 		break;
1649 
1650 	case LINUX_SIOCGIFADDR:
1651 		args->cmd = OSIOCGIFADDR;
1652 		error = ioctl(td, (struct ioctl_args *)args);
1653 		break;
1654 
1655 	case LINUX_SIOCGIFDSTADDR:
1656 		args->cmd = OSIOCGIFDSTADDR;
1657 		error = ioctl(td, (struct ioctl_args *)args);
1658 		break;
1659 
1660 	case LINUX_SIOCGIFBRDADDR:
1661 		args->cmd = OSIOCGIFBRDADDR;
1662 		error = ioctl(td, (struct ioctl_args *)args);
1663 		break;
1664 
1665 	case LINUX_SIOCGIFNETMASK:
1666 		args->cmd = OSIOCGIFNETMASK;
1667 		error = ioctl(td, (struct ioctl_args *)args);
1668 		break;
1669 
1670 	case LINUX_SIOCSIFNETMASK:
1671 		error = ENOIOCTL;
1672 		break;
1673 
1674 	case LINUX_SIOCGIFMTU:
1675 		args->cmd = SIOCGIFMTU;
1676 		error = ioctl(td, (struct ioctl_args *)args);
1677 		break;
1678 
1679 	case LINUX_SIOCSIFMTU:
1680 		args->cmd = SIOCSIFMTU;
1681 		error = ioctl(td, (struct ioctl_args *)args);
1682 		break;
1683 
1684 	case LINUX_SIOCSIFNAME:
1685 		error = ENOIOCTL;
1686 		break;
1687 
1688 	case LINUX_SIOCGIFHWADDR:
1689 		error = linux_gifhwaddr(ifp, (struct l_ifreq *)args->arg);
1690 		break;
1691 
1692 	case LINUX_SIOCSIFHWADDR:
1693 		error = ENOIOCTL;
1694 		break;
1695 
1696 	case LINUX_SIOCADDMULTI:
1697 		args->cmd = SIOCADDMULTI;
1698 		error = ioctl(td, (struct ioctl_args *)args);
1699 		break;
1700 
1701 	case LINUX_SIOCDELMULTI:
1702 		args->cmd = SIOCDELMULTI;
1703 		error = ioctl(td, (struct ioctl_args *)args);
1704 		break;
1705 
1706 	/*
1707 	 * XXX This is slightly bogus, but these ioctls are currently
1708 	 * XXX only used by the aironet (if_an) network driver.
1709 	 */
1710 	case LINUX_SIOCDEVPRIVATE:
1711 		args->cmd = SIOCGPRIVATE_0;
1712 		error = ioctl(td, (struct ioctl_args *)args);
1713 		break;
1714 
1715 	case LINUX_SIOCDEVPRIVATE+1:
1716 		args->cmd = SIOCGPRIVATE_1;
1717 		error = ioctl(td, (struct ioctl_args *)args);
1718 		break;
1719 	}
1720 
1721 	if (ifp != NULL)
1722 		/* restore the original interface name */
1723 		copyout(lifname, (char *)args->arg, LINUX_IFNAMSIZ);
1724 
1725 #ifdef DEBUG
1726 	printf(__FUNCTION__ "(): returning %d\n", error);
1727 #endif
1728 	return (error);
1729 }
1730 
1731 /*
1732  * Device private ioctl handler
1733  */
1734 static int
1735 linux_ioctl_private(struct thread *td, struct linux_ioctl_args *args)
1736 {
1737 	struct filedesc *fdp;
1738 	struct file *fp;
1739 	int type;
1740 
1741 	/* XXX is it sufficient to PROC_LOCK td->td_proc? */
1742 	mtx_lock(&Giant);
1743 	fdp = td->td_proc->p_fd;
1744 	if (args->fd >= fdp->fd_nfiles ||
1745 	    (fp = fdp->fd_ofiles[args->fd]) == NULL) {
1746 		mtx_unlock(&Giant);
1747 		return (EBADF);
1748 	} else {
1749 		type = fp->f_type;
1750 	}
1751 	mtx_unlock(&Giant);
1752 	if (type == DTYPE_SOCKET)
1753 		return (linux_ioctl_socket(td, args));
1754 	return (ioctl(td, (struct ioctl_args *)args));
1755 }
1756 
1757 /*
1758  * main ioctl syscall function
1759  */
1760 
1761 int
1762 linux_ioctl(struct thread *td, struct linux_ioctl_args *args)
1763 {
1764 	struct filedesc *fdp;
1765 	struct file *fp;
1766 	struct handler_element *he;
1767 	int error, cmd;
1768 
1769 #ifdef DEBUG
1770 	if (ldebug(ioctl))
1771 		printf(ARGS(ioctl, "%d, %04lx, *"), args->fd, args->cmd);
1772 #endif
1773 
1774 	fdp = td->td_proc->p_fd;
1775 	if ((unsigned)args->fd >= fdp->fd_nfiles)
1776 		return (EBADF);
1777 	fp = fdp->fd_ofiles[args->fd];
1778 	if (fp == NULL || (fp->f_flag & (FREAD|FWRITE)) == 0)
1779 		return (EBADF);
1780 
1781 	/* Iterate over the ioctl handlers */
1782 	cmd = args->cmd & 0xffff;
1783 	TAILQ_FOREACH(he, &handlers, list) {
1784 		if (cmd >= he->low && cmd <= he->high) {
1785 			error = (*he->func)(td, args);
1786 			if (error != ENOIOCTL)
1787 				return (error);
1788 		}
1789 	}
1790 
1791 	printf("linux: 'ioctl' fd=%d, cmd=0x%x ('%c',%d) not implemented\n",
1792 	    args->fd, (int)(args->cmd & 0xffff),
1793 	    (int)(args->cmd & 0xff00) >> 8, (int)(args->cmd & 0xff));
1794 
1795 	return (EINVAL);
1796 }
1797 
1798 int
1799 linux_ioctl_register_handler(struct linux_ioctl_handler *h)
1800 {
1801 	struct handler_element *he, *cur;
1802 
1803 	if (h == NULL || h->func == NULL)
1804 		return (EINVAL);
1805 
1806 	/*
1807 	 * Reuse the element if the handler is already on the list, otherwise
1808 	 * create a new element.
1809 	 */
1810 	TAILQ_FOREACH(he, &handlers, list) {
1811 		if (he->func == h->func)
1812 			break;
1813 	}
1814 	if (he == NULL) {
1815 		MALLOC(he, struct handler_element *, sizeof(*he),
1816 		    M_LINUX, M_WAITOK);
1817 		he->func = h->func;
1818 	} else
1819 		TAILQ_REMOVE(&handlers, he, list);
1820 
1821 	/* Initialize range information. */
1822 	he->low = h->low;
1823 	he->high = h->high;
1824 	he->span = h->high - h->low + 1;
1825 
1826 	/* Add the element to the list, sorted on span. */
1827 	TAILQ_FOREACH(cur, &handlers, list) {
1828 		if (cur->span > he->span) {
1829 			TAILQ_INSERT_BEFORE(cur, he, list);
1830 			return (0);
1831 		}
1832 	}
1833 	TAILQ_INSERT_TAIL(&handlers, he, list);
1834 
1835 	return (0);
1836 }
1837 
1838 int
1839 linux_ioctl_unregister_handler(struct linux_ioctl_handler *h)
1840 {
1841 	struct handler_element *he;
1842 
1843 	if (h == NULL || h->func == NULL)
1844 		return (EINVAL);
1845 
1846 	TAILQ_FOREACH(he, &handlers, list) {
1847 		if (he->func == h->func) {
1848 			TAILQ_REMOVE(&handlers, he, list);
1849 			FREE(he, M_LINUX);
1850 			return (0);
1851 		}
1852 	}
1853 
1854 	return (EINVAL);
1855 }
1856