linux_ioctl.c revision 202364
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 without 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
29#include "opt_compat.h"
30
31#include <sys/cdefs.h>
32__FBSDID("$FreeBSD: head/sys/compat/linux/linux_ioctl.c 202364 2010-01-15 14:58:19Z netchild $");
33
34#include <sys/param.h>
35#include <sys/systm.h>
36#include <sys/sysproto.h>
37#include <sys/cdio.h>
38#include <sys/dvdio.h>
39#include <sys/conf.h>
40#include <sys/disk.h>
41#include <sys/consio.h>
42#include <sys/ctype.h>
43#include <sys/fcntl.h>
44#include <sys/file.h>
45#include <sys/filedesc.h>
46#include <sys/filio.h>
47#include <sys/jail.h>
48#include <sys/kbio.h>
49#include <sys/kernel.h>
50#include <sys/linker_set.h>
51#include <sys/lock.h>
52#include <sys/malloc.h>
53#include <sys/proc.h>
54#include <sys/sbuf.h>
55#include <sys/socket.h>
56#include <sys/sockio.h>
57#include <sys/soundcard.h>
58#include <sys/stdint.h>
59#include <sys/sx.h>
60#include <sys/tty.h>
61#include <sys/uio.h>
62
63#include <net/if.h>
64#include <net/if_dl.h>
65#include <net/if_types.h>
66#include <net/vnet.h>
67
68#ifdef COMPAT_LINUX32
69#include <machine/../linux32/linux.h>
70#include <machine/../linux32/linux32_proto.h>
71#else
72#include <machine/../linux/linux.h>
73#include <machine/../linux/linux_proto.h>
74#endif
75
76#include <compat/linux/linux_ioctl.h>
77#include <compat/linux/linux_mib.h>
78#include <compat/linux/linux_socket.h>
79#include <compat/linux/linux_util.h>
80
81#include <compat/linux/linux_videodev.h>
82#include <compat/linux/linux_videodev_compat.h>
83
84CTASSERT(LINUX_IFNAMSIZ == IFNAMSIZ);
85
86static linux_ioctl_function_t linux_ioctl_cdrom;
87static linux_ioctl_function_t linux_ioctl_vfat;
88static linux_ioctl_function_t linux_ioctl_console;
89static linux_ioctl_function_t linux_ioctl_hdio;
90static linux_ioctl_function_t linux_ioctl_disk;
91static linux_ioctl_function_t linux_ioctl_socket;
92static linux_ioctl_function_t linux_ioctl_sound;
93static linux_ioctl_function_t linux_ioctl_termio;
94static linux_ioctl_function_t linux_ioctl_private;
95static linux_ioctl_function_t linux_ioctl_drm;
96static linux_ioctl_function_t linux_ioctl_sg;
97static linux_ioctl_function_t linux_ioctl_v4l;
98static linux_ioctl_function_t linux_ioctl_special;
99
100static struct linux_ioctl_handler cdrom_handler =
101{ linux_ioctl_cdrom, LINUX_IOCTL_CDROM_MIN, LINUX_IOCTL_CDROM_MAX };
102static struct linux_ioctl_handler vfat_handler =
103{ linux_ioctl_vfat, LINUX_IOCTL_VFAT_MIN, LINUX_IOCTL_VFAT_MAX };
104static struct linux_ioctl_handler console_handler =
105{ linux_ioctl_console, LINUX_IOCTL_CONSOLE_MIN, LINUX_IOCTL_CONSOLE_MAX };
106static struct linux_ioctl_handler hdio_handler =
107{ linux_ioctl_hdio, LINUX_IOCTL_HDIO_MIN, LINUX_IOCTL_HDIO_MAX };
108static struct linux_ioctl_handler disk_handler =
109{ linux_ioctl_disk, LINUX_IOCTL_DISK_MIN, LINUX_IOCTL_DISK_MAX };
110static struct linux_ioctl_handler socket_handler =
111{ linux_ioctl_socket, LINUX_IOCTL_SOCKET_MIN, LINUX_IOCTL_SOCKET_MAX };
112static struct linux_ioctl_handler sound_handler =
113{ linux_ioctl_sound, LINUX_IOCTL_SOUND_MIN, LINUX_IOCTL_SOUND_MAX };
114static struct linux_ioctl_handler termio_handler =
115{ linux_ioctl_termio, LINUX_IOCTL_TERMIO_MIN, LINUX_IOCTL_TERMIO_MAX };
116static struct linux_ioctl_handler private_handler =
117{ linux_ioctl_private, LINUX_IOCTL_PRIVATE_MIN, LINUX_IOCTL_PRIVATE_MAX };
118static struct linux_ioctl_handler drm_handler =
119{ linux_ioctl_drm, LINUX_IOCTL_DRM_MIN, LINUX_IOCTL_DRM_MAX };
120static struct linux_ioctl_handler sg_handler =
121{ linux_ioctl_sg, LINUX_IOCTL_SG_MIN, LINUX_IOCTL_SG_MAX };
122static struct linux_ioctl_handler video_handler =
123{ linux_ioctl_v4l, LINUX_IOCTL_VIDEO_MIN, LINUX_IOCTL_VIDEO_MAX };
124
125DATA_SET(linux_ioctl_handler_set, cdrom_handler);
126DATA_SET(linux_ioctl_handler_set, vfat_handler);
127DATA_SET(linux_ioctl_handler_set, console_handler);
128DATA_SET(linux_ioctl_handler_set, hdio_handler);
129DATA_SET(linux_ioctl_handler_set, disk_handler);
130DATA_SET(linux_ioctl_handler_set, socket_handler);
131DATA_SET(linux_ioctl_handler_set, sound_handler);
132DATA_SET(linux_ioctl_handler_set, termio_handler);
133DATA_SET(linux_ioctl_handler_set, private_handler);
134DATA_SET(linux_ioctl_handler_set, drm_handler);
135DATA_SET(linux_ioctl_handler_set, sg_handler);
136DATA_SET(linux_ioctl_handler_set, video_handler);
137
138struct handler_element
139{
140	TAILQ_ENTRY(handler_element) list;
141	int	(*func)(struct thread *, struct linux_ioctl_args *);
142	int	low, high, span;
143};
144
145static TAILQ_HEAD(, handler_element) handlers =
146	TAILQ_HEAD_INITIALIZER(handlers);
147static struct sx linux_ioctl_sx;
148SX_SYSINIT(linux_ioctl, &linux_ioctl_sx, "linux ioctl handlers");
149
150/*
151 * hdio related ioctls for VMWare support
152 */
153
154struct linux_hd_geometry {
155	u_int8_t	heads;
156	u_int8_t	sectors;
157	u_int16_t	cylinders;
158	u_int32_t	start;
159};
160
161struct linux_hd_big_geometry {
162	u_int8_t	heads;
163	u_int8_t	sectors;
164	u_int32_t	cylinders;
165	u_int32_t	start;
166};
167
168static int
169linux_ioctl_hdio(struct thread *td, struct linux_ioctl_args *args)
170{
171	struct file *fp;
172	int error;
173	u_int sectorsize, fwcylinders, fwheads, fwsectors;
174	off_t mediasize, bytespercyl;
175
176	if ((error = fget(td, args->fd, &fp)) != 0)
177		return (error);
178	switch (args->cmd & 0xffff) {
179	case LINUX_HDIO_GET_GEO:
180	case LINUX_HDIO_GET_GEO_BIG:
181		error = fo_ioctl(fp, DIOCGMEDIASIZE,
182			(caddr_t)&mediasize, td->td_ucred, td);
183		if (!error)
184			error = fo_ioctl(fp, DIOCGSECTORSIZE,
185				(caddr_t)&sectorsize, td->td_ucred, td);
186		if (!error)
187			error = fo_ioctl(fp, DIOCGFWHEADS,
188				(caddr_t)&fwheads, td->td_ucred, td);
189		if (!error)
190			error = fo_ioctl(fp, DIOCGFWSECTORS,
191				(caddr_t)&fwsectors, td->td_ucred, td);
192		/*
193		 * XXX: DIOCGFIRSTOFFSET is not yet implemented, so
194		 * so pretend that GEOM always says 0. This is NOT VALID
195		 * for slices or partitions, only the per-disk raw devices.
196		 */
197
198		fdrop(fp, td);
199		if (error)
200			return (error);
201		/*
202		 * 1. Calculate the number of bytes in a cylinder,
203		 *    given the firmware's notion of heads and sectors
204		 *    per cylinder.
205		 * 2. Calculate the number of cylinders, given the total
206		 *    size of the media.
207		 * All internal calculations should have 64-bit precision.
208		 */
209		bytespercyl = (off_t) sectorsize * fwheads * fwsectors;
210		fwcylinders = mediasize / bytespercyl;
211#if defined(DEBUG)
212		linux_msg(td, "HDIO_GET_GEO: mediasize %jd, c/h/s %d/%d/%d, "
213			  "bpc %jd",
214			  (intmax_t)mediasize, fwcylinders, fwheads, fwsectors,
215			  (intmax_t)bytespercyl);
216#endif
217		if ((args->cmd & 0xffff) == LINUX_HDIO_GET_GEO) {
218			struct linux_hd_geometry hdg;
219
220			hdg.cylinders = fwcylinders;
221			hdg.heads = fwheads;
222			hdg.sectors = fwsectors;
223			hdg.start = 0;
224			error = copyout(&hdg, (void *)args->arg, sizeof(hdg));
225		} else if ((args->cmd & 0xffff) == LINUX_HDIO_GET_GEO_BIG) {
226			struct linux_hd_big_geometry hdbg;
227
228			hdbg.cylinders = fwcylinders;
229			hdbg.heads = fwheads;
230			hdbg.sectors = fwsectors;
231			hdbg.start = 0;
232			error = copyout(&hdbg, (void *)args->arg, sizeof(hdbg));
233		}
234		return (error);
235		break;
236	default:
237		/* XXX */
238		linux_msg(td,
239			"ioctl fd=%d, cmd=0x%x ('%c',%d) is not implemented",
240			args->fd, (int)(args->cmd & 0xffff),
241			(int)(args->cmd & 0xff00) >> 8,
242			(int)(args->cmd & 0xff));
243		break;
244	}
245	fdrop(fp, td);
246	return (ENOIOCTL);
247}
248
249static int
250linux_ioctl_disk(struct thread *td, struct linux_ioctl_args *args)
251{
252	struct file *fp;
253	int error;
254	u_int sectorsize;
255	off_t mediasize;
256
257	if ((error = fget(td, args->fd, &fp)) != 0)
258		return (error);
259	switch (args->cmd & 0xffff) {
260	case LINUX_BLKGETSIZE:
261		error = fo_ioctl(fp, DIOCGSECTORSIZE,
262		    (caddr_t)&sectorsize, td->td_ucred, td);
263		if (!error)
264			error = fo_ioctl(fp, DIOCGMEDIASIZE,
265			    (caddr_t)&mediasize, td->td_ucred, td);
266		fdrop(fp, td);
267		if (error)
268			return (error);
269		sectorsize = mediasize / sectorsize;
270		/*
271		 * XXX: How do we know we return the right size of integer ?
272		 */
273		return (copyout(&sectorsize, (void *)args->arg,
274		    sizeof(sectorsize)));
275		break;
276	}
277	fdrop(fp, td);
278	return (ENOIOCTL);
279}
280
281/*
282 * termio related ioctls
283 */
284
285struct linux_termio {
286	unsigned short c_iflag;
287	unsigned short c_oflag;
288	unsigned short c_cflag;
289	unsigned short c_lflag;
290	unsigned char c_line;
291	unsigned char c_cc[LINUX_NCC];
292};
293
294struct linux_termios {
295	unsigned int c_iflag;
296	unsigned int c_oflag;
297	unsigned int c_cflag;
298	unsigned int c_lflag;
299	unsigned char c_line;
300	unsigned char c_cc[LINUX_NCCS];
301};
302
303struct linux_winsize {
304	unsigned short ws_row, ws_col;
305	unsigned short ws_xpixel, ws_ypixel;
306};
307
308struct speedtab {
309	int sp_speed;			/* Speed. */
310	int sp_code;			/* Code. */
311};
312
313static struct speedtab sptab[] = {
314	{ B0, LINUX_B0 }, { B50, LINUX_B50 },
315	{ B75, LINUX_B75 }, { B110, LINUX_B110 },
316	{ B134, LINUX_B134 }, { B150, LINUX_B150 },
317	{ B200, LINUX_B200 }, { B300, LINUX_B300 },
318	{ B600, LINUX_B600 }, { B1200, LINUX_B1200 },
319	{ B1800, LINUX_B1800 }, { B2400, LINUX_B2400 },
320	{ B4800, LINUX_B4800 }, { B9600, LINUX_B9600 },
321	{ B19200, LINUX_B19200 }, { B38400, LINUX_B38400 },
322	{ B57600, LINUX_B57600 }, { B115200, LINUX_B115200 },
323	{-1, -1 }
324};
325
326struct linux_serial_struct {
327	int	type;
328	int	line;
329	int	port;
330	int	irq;
331	int	flags;
332	int	xmit_fifo_size;
333	int	custom_divisor;
334	int	baud_base;
335	unsigned short close_delay;
336	char	reserved_char[2];
337	int	hub6;
338	unsigned short closing_wait;
339	unsigned short closing_wait2;
340	int	reserved[4];
341};
342
343static int
344linux_to_bsd_speed(int code, struct speedtab *table)
345{
346	for ( ; table->sp_code != -1; table++)
347		if (table->sp_code == code)
348			return (table->sp_speed);
349	return -1;
350}
351
352static int
353bsd_to_linux_speed(int speed, struct speedtab *table)
354{
355	for ( ; table->sp_speed != -1; table++)
356		if (table->sp_speed == speed)
357			return (table->sp_code);
358	return -1;
359}
360
361static void
362bsd_to_linux_termios(struct termios *bios, struct linux_termios *lios)
363{
364	int i;
365
366#ifdef DEBUG
367	if (ldebug(ioctl)) {
368		printf("LINUX: BSD termios structure (input):\n");
369		printf("i=%08x o=%08x c=%08x l=%08x ispeed=%d ospeed=%d\n",
370		    bios->c_iflag, bios->c_oflag, bios->c_cflag, bios->c_lflag,
371		    bios->c_ispeed, bios->c_ospeed);
372		printf("c_cc ");
373		for (i=0; i<NCCS; i++)
374			printf("%02x ", bios->c_cc[i]);
375		printf("\n");
376	}
377#endif
378
379	lios->c_iflag = 0;
380	if (bios->c_iflag & IGNBRK)
381		lios->c_iflag |= LINUX_IGNBRK;
382	if (bios->c_iflag & BRKINT)
383		lios->c_iflag |= LINUX_BRKINT;
384	if (bios->c_iflag & IGNPAR)
385		lios->c_iflag |= LINUX_IGNPAR;
386	if (bios->c_iflag & PARMRK)
387		lios->c_iflag |= LINUX_PARMRK;
388	if (bios->c_iflag & INPCK)
389		lios->c_iflag |= LINUX_INPCK;
390	if (bios->c_iflag & ISTRIP)
391		lios->c_iflag |= LINUX_ISTRIP;
392	if (bios->c_iflag & INLCR)
393		lios->c_iflag |= LINUX_INLCR;
394	if (bios->c_iflag & IGNCR)
395		lios->c_iflag |= LINUX_IGNCR;
396	if (bios->c_iflag & ICRNL)
397		lios->c_iflag |= LINUX_ICRNL;
398	if (bios->c_iflag & IXON)
399		lios->c_iflag |= LINUX_IXON;
400	if (bios->c_iflag & IXANY)
401		lios->c_iflag |= LINUX_IXANY;
402	if (bios->c_iflag & IXOFF)
403		lios->c_iflag |= LINUX_IXOFF;
404	if (bios->c_iflag & IMAXBEL)
405		lios->c_iflag |= LINUX_IMAXBEL;
406
407	lios->c_oflag = 0;
408	if (bios->c_oflag & OPOST)
409		lios->c_oflag |= LINUX_OPOST;
410	if (bios->c_oflag & ONLCR)
411		lios->c_oflag |= LINUX_ONLCR;
412	if (bios->c_oflag & TAB3)
413		lios->c_oflag |= LINUX_XTABS;
414
415	lios->c_cflag = bsd_to_linux_speed(bios->c_ispeed, sptab);
416	lios->c_cflag |= (bios->c_cflag & CSIZE) >> 4;
417	if (bios->c_cflag & CSTOPB)
418		lios->c_cflag |= LINUX_CSTOPB;
419	if (bios->c_cflag & CREAD)
420		lios->c_cflag |= LINUX_CREAD;
421	if (bios->c_cflag & PARENB)
422		lios->c_cflag |= LINUX_PARENB;
423	if (bios->c_cflag & PARODD)
424		lios->c_cflag |= LINUX_PARODD;
425	if (bios->c_cflag & HUPCL)
426		lios->c_cflag |= LINUX_HUPCL;
427	if (bios->c_cflag & CLOCAL)
428		lios->c_cflag |= LINUX_CLOCAL;
429	if (bios->c_cflag & CRTSCTS)
430		lios->c_cflag |= LINUX_CRTSCTS;
431
432	lios->c_lflag = 0;
433	if (bios->c_lflag & ISIG)
434		lios->c_lflag |= LINUX_ISIG;
435	if (bios->c_lflag & ICANON)
436		lios->c_lflag |= LINUX_ICANON;
437	if (bios->c_lflag & ECHO)
438		lios->c_lflag |= LINUX_ECHO;
439	if (bios->c_lflag & ECHOE)
440		lios->c_lflag |= LINUX_ECHOE;
441	if (bios->c_lflag & ECHOK)
442		lios->c_lflag |= LINUX_ECHOK;
443	if (bios->c_lflag & ECHONL)
444		lios->c_lflag |= LINUX_ECHONL;
445	if (bios->c_lflag & NOFLSH)
446		lios->c_lflag |= LINUX_NOFLSH;
447	if (bios->c_lflag & TOSTOP)
448		lios->c_lflag |= LINUX_TOSTOP;
449	if (bios->c_lflag & ECHOCTL)
450		lios->c_lflag |= LINUX_ECHOCTL;
451	if (bios->c_lflag & ECHOPRT)
452		lios->c_lflag |= LINUX_ECHOPRT;
453	if (bios->c_lflag & ECHOKE)
454		lios->c_lflag |= LINUX_ECHOKE;
455	if (bios->c_lflag & FLUSHO)
456		lios->c_lflag |= LINUX_FLUSHO;
457	if (bios->c_lflag & PENDIN)
458		lios->c_lflag |= LINUX_PENDIN;
459	if (bios->c_lflag & IEXTEN)
460		lios->c_lflag |= LINUX_IEXTEN;
461
462	for (i=0; i<LINUX_NCCS; i++)
463		lios->c_cc[i] = LINUX_POSIX_VDISABLE;
464	lios->c_cc[LINUX_VINTR] = bios->c_cc[VINTR];
465	lios->c_cc[LINUX_VQUIT] = bios->c_cc[VQUIT];
466	lios->c_cc[LINUX_VERASE] = bios->c_cc[VERASE];
467	lios->c_cc[LINUX_VKILL] = bios->c_cc[VKILL];
468	lios->c_cc[LINUX_VEOF] = bios->c_cc[VEOF];
469	lios->c_cc[LINUX_VEOL] = bios->c_cc[VEOL];
470	lios->c_cc[LINUX_VMIN] = bios->c_cc[VMIN];
471	lios->c_cc[LINUX_VTIME] = bios->c_cc[VTIME];
472	lios->c_cc[LINUX_VEOL2] = bios->c_cc[VEOL2];
473	lios->c_cc[LINUX_VSUSP] = bios->c_cc[VSUSP];
474	lios->c_cc[LINUX_VSTART] = bios->c_cc[VSTART];
475	lios->c_cc[LINUX_VSTOP] = bios->c_cc[VSTOP];
476	lios->c_cc[LINUX_VREPRINT] = bios->c_cc[VREPRINT];
477	lios->c_cc[LINUX_VDISCARD] = bios->c_cc[VDISCARD];
478	lios->c_cc[LINUX_VWERASE] = bios->c_cc[VWERASE];
479	lios->c_cc[LINUX_VLNEXT] = bios->c_cc[VLNEXT];
480
481	for (i=0; i<LINUX_NCCS; i++) {
482		if (i != LINUX_VMIN && i != LINUX_VTIME &&
483		    lios->c_cc[i] == _POSIX_VDISABLE)
484			lios->c_cc[i] = LINUX_POSIX_VDISABLE;
485	}
486	lios->c_line = 0;
487
488#ifdef DEBUG
489	if (ldebug(ioctl)) {
490		printf("LINUX: LINUX termios structure (output):\n");
491		printf("i=%08x o=%08x c=%08x l=%08x line=%d\n",
492		    lios->c_iflag, lios->c_oflag, lios->c_cflag,
493		    lios->c_lflag, (int)lios->c_line);
494		printf("c_cc ");
495		for (i=0; i<LINUX_NCCS; i++)
496			printf("%02x ", lios->c_cc[i]);
497		printf("\n");
498	}
499#endif
500}
501
502static void
503linux_to_bsd_termios(struct linux_termios *lios, struct termios *bios)
504{
505	int i;
506
507#ifdef DEBUG
508	if (ldebug(ioctl)) {
509		printf("LINUX: LINUX termios structure (input):\n");
510		printf("i=%08x o=%08x c=%08x l=%08x line=%d\n",
511		    lios->c_iflag, lios->c_oflag, lios->c_cflag,
512		    lios->c_lflag, (int)lios->c_line);
513		printf("c_cc ");
514		for (i=0; i<LINUX_NCCS; i++)
515			printf("%02x ", lios->c_cc[i]);
516		printf("\n");
517	}
518#endif
519
520	bios->c_iflag = 0;
521	if (lios->c_iflag & LINUX_IGNBRK)
522		bios->c_iflag |= IGNBRK;
523	if (lios->c_iflag & LINUX_BRKINT)
524		bios->c_iflag |= BRKINT;
525	if (lios->c_iflag & LINUX_IGNPAR)
526		bios->c_iflag |= IGNPAR;
527	if (lios->c_iflag & LINUX_PARMRK)
528		bios->c_iflag |= PARMRK;
529	if (lios->c_iflag & LINUX_INPCK)
530		bios->c_iflag |= INPCK;
531	if (lios->c_iflag & LINUX_ISTRIP)
532		bios->c_iflag |= ISTRIP;
533	if (lios->c_iflag & LINUX_INLCR)
534		bios->c_iflag |= INLCR;
535	if (lios->c_iflag & LINUX_IGNCR)
536		bios->c_iflag |= IGNCR;
537	if (lios->c_iflag & LINUX_ICRNL)
538		bios->c_iflag |= ICRNL;
539	if (lios->c_iflag & LINUX_IXON)
540		bios->c_iflag |= IXON;
541	if (lios->c_iflag & LINUX_IXANY)
542		bios->c_iflag |= IXANY;
543	if (lios->c_iflag & LINUX_IXOFF)
544		bios->c_iflag |= IXOFF;
545	if (lios->c_iflag & LINUX_IMAXBEL)
546		bios->c_iflag |= IMAXBEL;
547
548	bios->c_oflag = 0;
549	if (lios->c_oflag & LINUX_OPOST)
550		bios->c_oflag |= OPOST;
551	if (lios->c_oflag & LINUX_ONLCR)
552		bios->c_oflag |= ONLCR;
553	if (lios->c_oflag & LINUX_XTABS)
554		bios->c_oflag |= TAB3;
555
556	bios->c_cflag = (lios->c_cflag & LINUX_CSIZE) << 4;
557	if (lios->c_cflag & LINUX_CSTOPB)
558		bios->c_cflag |= CSTOPB;
559	if (lios->c_cflag & LINUX_CREAD)
560		bios->c_cflag |= CREAD;
561	if (lios->c_cflag & LINUX_PARENB)
562		bios->c_cflag |= PARENB;
563	if (lios->c_cflag & LINUX_PARODD)
564		bios->c_cflag |= PARODD;
565	if (lios->c_cflag & LINUX_HUPCL)
566		bios->c_cflag |= HUPCL;
567	if (lios->c_cflag & LINUX_CLOCAL)
568		bios->c_cflag |= CLOCAL;
569	if (lios->c_cflag & LINUX_CRTSCTS)
570		bios->c_cflag |= CRTSCTS;
571
572	bios->c_lflag = 0;
573	if (lios->c_lflag & LINUX_ISIG)
574		bios->c_lflag |= ISIG;
575	if (lios->c_lflag & LINUX_ICANON)
576		bios->c_lflag |= ICANON;
577	if (lios->c_lflag & LINUX_ECHO)
578		bios->c_lflag |= ECHO;
579	if (lios->c_lflag & LINUX_ECHOE)
580		bios->c_lflag |= ECHOE;
581	if (lios->c_lflag & LINUX_ECHOK)
582		bios->c_lflag |= ECHOK;
583	if (lios->c_lflag & LINUX_ECHONL)
584		bios->c_lflag |= ECHONL;
585	if (lios->c_lflag & LINUX_NOFLSH)
586		bios->c_lflag |= NOFLSH;
587	if (lios->c_lflag & LINUX_TOSTOP)
588		bios->c_lflag |= TOSTOP;
589	if (lios->c_lflag & LINUX_ECHOCTL)
590		bios->c_lflag |= ECHOCTL;
591	if (lios->c_lflag & LINUX_ECHOPRT)
592		bios->c_lflag |= ECHOPRT;
593	if (lios->c_lflag & LINUX_ECHOKE)
594		bios->c_lflag |= ECHOKE;
595	if (lios->c_lflag & LINUX_FLUSHO)
596		bios->c_lflag |= FLUSHO;
597	if (lios->c_lflag & LINUX_PENDIN)
598		bios->c_lflag |= PENDIN;
599	if (lios->c_lflag & LINUX_IEXTEN)
600		bios->c_lflag |= IEXTEN;
601
602	for (i=0; i<NCCS; i++)
603		bios->c_cc[i] = _POSIX_VDISABLE;
604	bios->c_cc[VINTR] = lios->c_cc[LINUX_VINTR];
605	bios->c_cc[VQUIT] = lios->c_cc[LINUX_VQUIT];
606	bios->c_cc[VERASE] = lios->c_cc[LINUX_VERASE];
607	bios->c_cc[VKILL] = lios->c_cc[LINUX_VKILL];
608	bios->c_cc[VEOF] = lios->c_cc[LINUX_VEOF];
609	bios->c_cc[VEOL] = lios->c_cc[LINUX_VEOL];
610	bios->c_cc[VMIN] = lios->c_cc[LINUX_VMIN];
611	bios->c_cc[VTIME] = lios->c_cc[LINUX_VTIME];
612	bios->c_cc[VEOL2] = lios->c_cc[LINUX_VEOL2];
613	bios->c_cc[VSUSP] = lios->c_cc[LINUX_VSUSP];
614	bios->c_cc[VSTART] = lios->c_cc[LINUX_VSTART];
615	bios->c_cc[VSTOP] = lios->c_cc[LINUX_VSTOP];
616	bios->c_cc[VREPRINT] = lios->c_cc[LINUX_VREPRINT];
617	bios->c_cc[VDISCARD] = lios->c_cc[LINUX_VDISCARD];
618	bios->c_cc[VWERASE] = lios->c_cc[LINUX_VWERASE];
619	bios->c_cc[VLNEXT] = lios->c_cc[LINUX_VLNEXT];
620
621	for (i=0; i<NCCS; i++) {
622		if (i != VMIN && i != VTIME &&
623		    bios->c_cc[i] == LINUX_POSIX_VDISABLE)
624			bios->c_cc[i] = _POSIX_VDISABLE;
625	}
626
627	bios->c_ispeed = bios->c_ospeed =
628	    linux_to_bsd_speed(lios->c_cflag & LINUX_CBAUD, sptab);
629
630#ifdef DEBUG
631	if (ldebug(ioctl)) {
632		printf("LINUX: BSD termios structure (output):\n");
633		printf("i=%08x o=%08x c=%08x l=%08x ispeed=%d ospeed=%d\n",
634		    bios->c_iflag, bios->c_oflag, bios->c_cflag, bios->c_lflag,
635		    bios->c_ispeed, bios->c_ospeed);
636		printf("c_cc ");
637		for (i=0; i<NCCS; i++)
638			printf("%02x ", bios->c_cc[i]);
639		printf("\n");
640	}
641#endif
642}
643
644static void
645bsd_to_linux_termio(struct termios *bios, struct linux_termio *lio)
646{
647	struct linux_termios lios;
648
649	bsd_to_linux_termios(bios, &lios);
650	lio->c_iflag = lios.c_iflag;
651	lio->c_oflag = lios.c_oflag;
652	lio->c_cflag = lios.c_cflag;
653	lio->c_lflag = lios.c_lflag;
654	lio->c_line  = lios.c_line;
655	memcpy(lio->c_cc, lios.c_cc, LINUX_NCC);
656}
657
658static void
659linux_to_bsd_termio(struct linux_termio *lio, struct termios *bios)
660{
661	struct linux_termios lios;
662	int i;
663
664	lios.c_iflag = lio->c_iflag;
665	lios.c_oflag = lio->c_oflag;
666	lios.c_cflag = lio->c_cflag;
667	lios.c_lflag = lio->c_lflag;
668	for (i=LINUX_NCC; i<LINUX_NCCS; i++)
669		lios.c_cc[i] = LINUX_POSIX_VDISABLE;
670	memcpy(lios.c_cc, lio->c_cc, LINUX_NCC);
671	linux_to_bsd_termios(&lios, bios);
672}
673
674static int
675linux_ioctl_termio(struct thread *td, struct linux_ioctl_args *args)
676{
677	struct termios bios;
678	struct linux_termios lios;
679	struct linux_termio lio;
680	struct file *fp;
681	int error;
682
683	if ((error = fget(td, args->fd, &fp)) != 0)
684		return (error);
685
686	switch (args->cmd & 0xffff) {
687
688	case LINUX_TCGETS:
689		error = fo_ioctl(fp, TIOCGETA, (caddr_t)&bios, td->td_ucred,
690		    td);
691		if (error)
692			break;
693		bsd_to_linux_termios(&bios, &lios);
694		error = copyout(&lios, (void *)args->arg, sizeof(lios));
695		break;
696
697	case LINUX_TCSETS:
698		error = copyin((void *)args->arg, &lios, sizeof(lios));
699		if (error)
700			break;
701		linux_to_bsd_termios(&lios, &bios);
702		error = (fo_ioctl(fp, TIOCSETA, (caddr_t)&bios, td->td_ucred,
703		    td));
704		break;
705
706	case LINUX_TCSETSW:
707		error = copyin((void *)args->arg, &lios, sizeof(lios));
708		if (error)
709			break;
710		linux_to_bsd_termios(&lios, &bios);
711		error = (fo_ioctl(fp, TIOCSETAW, (caddr_t)&bios, td->td_ucred,
712		    td));
713		break;
714
715	case LINUX_TCSETSF:
716		error = copyin((void *)args->arg, &lios, sizeof(lios));
717		if (error)
718			break;
719		linux_to_bsd_termios(&lios, &bios);
720		error = (fo_ioctl(fp, TIOCSETAF, (caddr_t)&bios, td->td_ucred,
721		    td));
722		break;
723
724	case LINUX_TCGETA:
725		error = fo_ioctl(fp, TIOCGETA, (caddr_t)&bios, td->td_ucred,
726		    td);
727		if (error)
728			break;
729		bsd_to_linux_termio(&bios, &lio);
730		error = (copyout(&lio, (void *)args->arg, sizeof(lio)));
731		break;
732
733	case LINUX_TCSETA:
734		error = copyin((void *)args->arg, &lio, sizeof(lio));
735		if (error)
736			break;
737		linux_to_bsd_termio(&lio, &bios);
738		error = (fo_ioctl(fp, TIOCSETA, (caddr_t)&bios, td->td_ucred,
739		    td));
740		break;
741
742	case LINUX_TCSETAW:
743		error = copyin((void *)args->arg, &lio, sizeof(lio));
744		if (error)
745			break;
746		linux_to_bsd_termio(&lio, &bios);
747		error = (fo_ioctl(fp, TIOCSETAW, (caddr_t)&bios, td->td_ucred,
748		    td));
749		break;
750
751	case LINUX_TCSETAF:
752		error = copyin((void *)args->arg, &lio, sizeof(lio));
753		if (error)
754			break;
755		linux_to_bsd_termio(&lio, &bios);
756		error = (fo_ioctl(fp, TIOCSETAF, (caddr_t)&bios, td->td_ucred,
757		    td));
758		break;
759
760	/* LINUX_TCSBRK */
761
762	case LINUX_TCXONC: {
763		switch (args->arg) {
764		case LINUX_TCOOFF:
765			args->cmd = TIOCSTOP;
766			break;
767		case LINUX_TCOON:
768			args->cmd = TIOCSTART;
769			break;
770		case LINUX_TCIOFF:
771		case LINUX_TCION: {
772			int c;
773			struct write_args wr;
774			error = fo_ioctl(fp, TIOCGETA, (caddr_t)&bios,
775			    td->td_ucred, td);
776			if (error)
777				break;
778			fdrop(fp, td);
779			c = (args->arg == LINUX_TCIOFF) ? VSTOP : VSTART;
780			c = bios.c_cc[c];
781			if (c != _POSIX_VDISABLE) {
782				wr.fd = args->fd;
783				wr.buf = &c;
784				wr.nbyte = sizeof(c);
785				return (write(td, &wr));
786			} else
787				return (0);
788		}
789		default:
790			fdrop(fp, td);
791			return (EINVAL);
792		}
793		args->arg = 0;
794		error = (ioctl(td, (struct ioctl_args *)args));
795		break;
796	}
797
798	case LINUX_TCFLSH: {
799		int val;
800		switch (args->arg) {
801		case LINUX_TCIFLUSH:
802			val = FREAD;
803			break;
804		case LINUX_TCOFLUSH:
805			val = FWRITE;
806			break;
807		case LINUX_TCIOFLUSH:
808			val = FREAD | FWRITE;
809			break;
810		default:
811			fdrop(fp, td);
812			return (EINVAL);
813		}
814		error = (fo_ioctl(fp,TIOCFLUSH,(caddr_t)&val,td->td_ucred,td));
815		break;
816	}
817
818	case LINUX_TIOCEXCL:
819		args->cmd = TIOCEXCL;
820		error = (ioctl(td, (struct ioctl_args *)args));
821		break;
822
823	case LINUX_TIOCNXCL:
824		args->cmd = TIOCNXCL;
825		error = (ioctl(td, (struct ioctl_args *)args));
826		break;
827
828	case LINUX_TIOCSCTTY:
829		args->cmd = TIOCSCTTY;
830		error = (ioctl(td, (struct ioctl_args *)args));
831		break;
832
833	case LINUX_TIOCGPGRP:
834		args->cmd = TIOCGPGRP;
835		error = (ioctl(td, (struct ioctl_args *)args));
836		break;
837
838	case LINUX_TIOCSPGRP:
839		args->cmd = TIOCSPGRP;
840		error = (ioctl(td, (struct ioctl_args *)args));
841		break;
842
843	/* LINUX_TIOCOUTQ */
844	/* LINUX_TIOCSTI */
845
846	case LINUX_TIOCGWINSZ:
847		args->cmd = TIOCGWINSZ;
848		error = (ioctl(td, (struct ioctl_args *)args));
849		break;
850
851	case LINUX_TIOCSWINSZ:
852		args->cmd = TIOCSWINSZ;
853		error = (ioctl(td, (struct ioctl_args *)args));
854		break;
855
856	case LINUX_TIOCMGET:
857		args->cmd = TIOCMGET;
858		error = (ioctl(td, (struct ioctl_args *)args));
859		break;
860
861	case LINUX_TIOCMBIS:
862		args->cmd = TIOCMBIS;
863		error = (ioctl(td, (struct ioctl_args *)args));
864		break;
865
866	case LINUX_TIOCMBIC:
867		args->cmd = TIOCMBIC;
868		error = (ioctl(td, (struct ioctl_args *)args));
869		break;
870
871	case LINUX_TIOCMSET:
872		args->cmd = TIOCMSET;
873		error = (ioctl(td, (struct ioctl_args *)args));
874		break;
875
876	/* TIOCGSOFTCAR */
877	/* TIOCSSOFTCAR */
878
879	case LINUX_FIONREAD: /* LINUX_TIOCINQ */
880		args->cmd = FIONREAD;
881		error = (ioctl(td, (struct ioctl_args *)args));
882		break;
883
884	/* LINUX_TIOCLINUX */
885
886	case LINUX_TIOCCONS:
887		args->cmd = TIOCCONS;
888		error = (ioctl(td, (struct ioctl_args *)args));
889		break;
890
891	case LINUX_TIOCGSERIAL: {
892		struct linux_serial_struct lss;
893		lss.type = LINUX_PORT_16550A;
894		lss.flags = 0;
895		lss.close_delay = 0;
896		error = copyout(&lss, (void *)args->arg, sizeof(lss));
897		break;
898	}
899
900	case LINUX_TIOCSSERIAL: {
901		struct linux_serial_struct lss;
902		error = copyin((void *)args->arg, &lss, sizeof(lss));
903		if (error)
904			break;
905		/* XXX - It really helps to have an implementation that
906		 * does nothing. NOT!
907		 */
908		error = 0;
909		break;
910	}
911
912	case LINUX_TIOCPKT:
913		args->cmd = TIOCPKT;
914		error = (ioctl(td, (struct ioctl_args *)args));
915		break;
916
917	case LINUX_FIONBIO:
918		args->cmd = FIONBIO;
919		error = (ioctl(td, (struct ioctl_args *)args));
920		break;
921
922	case LINUX_TIOCNOTTY:
923		args->cmd = TIOCNOTTY;
924		error = (ioctl(td, (struct ioctl_args *)args));
925		break;
926
927	case LINUX_TIOCSETD: {
928		int line;
929		switch (args->arg) {
930		case LINUX_N_TTY:
931			line = TTYDISC;
932			break;
933		case LINUX_N_SLIP:
934			line = SLIPDISC;
935			break;
936		case LINUX_N_PPP:
937			line = PPPDISC;
938			break;
939		default:
940			fdrop(fp, td);
941			return (EINVAL);
942		}
943		error = (fo_ioctl(fp, TIOCSETD, (caddr_t)&line, td->td_ucred,
944		    td));
945		break;
946	}
947
948	case LINUX_TIOCGETD: {
949		int linux_line;
950		int bsd_line = TTYDISC;
951		error = fo_ioctl(fp, TIOCGETD, (caddr_t)&bsd_line,
952		    td->td_ucred, td);
953		if (error)
954			return (error);
955		switch (bsd_line) {
956		case TTYDISC:
957			linux_line = LINUX_N_TTY;
958			break;
959		case SLIPDISC:
960			linux_line = LINUX_N_SLIP;
961			break;
962		case PPPDISC:
963			linux_line = LINUX_N_PPP;
964			break;
965		default:
966			fdrop(fp, td);
967			return (EINVAL);
968		}
969		error = (copyout(&linux_line, (void *)args->arg, sizeof(int)));
970		break;
971	}
972
973	/* LINUX_TCSBRKP */
974	/* LINUX_TIOCTTYGSTRUCT */
975
976	case LINUX_FIONCLEX:
977		args->cmd = FIONCLEX;
978		error = (ioctl(td, (struct ioctl_args *)args));
979		break;
980
981	case LINUX_FIOCLEX:
982		args->cmd = FIOCLEX;
983		error = (ioctl(td, (struct ioctl_args *)args));
984		break;
985
986	case LINUX_FIOASYNC:
987		args->cmd = FIOASYNC;
988		error = (ioctl(td, (struct ioctl_args *)args));
989		break;
990
991	/* LINUX_TIOCSERCONFIG */
992	/* LINUX_TIOCSERGWILD */
993	/* LINUX_TIOCSERSWILD */
994	/* LINUX_TIOCGLCKTRMIOS */
995	/* LINUX_TIOCSLCKTRMIOS */
996
997	case LINUX_TIOCSBRK:
998		args->cmd = TIOCSBRK;
999		error = (ioctl(td, (struct ioctl_args *)args));
1000		break;
1001
1002	case LINUX_TIOCCBRK:
1003		args->cmd = TIOCCBRK;
1004		error = (ioctl(td, (struct ioctl_args *)args));
1005		break;
1006	case LINUX_TIOCGPTN: {
1007		int nb;
1008
1009		error = fo_ioctl(fp, TIOCGPTN, (caddr_t)&nb, td->td_ucred, td);
1010		if (!error)
1011			error = copyout(&nb, (void *)args->arg,
1012			    sizeof(int));
1013		break;
1014	}
1015	case LINUX_TIOCSPTLCK:
1016		/* Our unlockpt() does nothing. */
1017		error = 0;
1018		break;
1019	default:
1020		error = ENOIOCTL;
1021		break;
1022	}
1023
1024	fdrop(fp, td);
1025	return (error);
1026}
1027
1028/*
1029 * CDROM related ioctls
1030 */
1031
1032struct linux_cdrom_msf
1033{
1034	u_char	cdmsf_min0;
1035	u_char	cdmsf_sec0;
1036	u_char	cdmsf_frame0;
1037	u_char	cdmsf_min1;
1038	u_char	cdmsf_sec1;
1039	u_char	cdmsf_frame1;
1040};
1041
1042struct linux_cdrom_tochdr
1043{
1044	u_char	cdth_trk0;
1045	u_char	cdth_trk1;
1046};
1047
1048union linux_cdrom_addr
1049{
1050	struct {
1051		u_char	minute;
1052		u_char	second;
1053		u_char	frame;
1054	} msf;
1055	int	lba;
1056};
1057
1058struct linux_cdrom_tocentry
1059{
1060	u_char	cdte_track;
1061	u_char	cdte_adr:4;
1062	u_char	cdte_ctrl:4;
1063	u_char	cdte_format;
1064	union linux_cdrom_addr cdte_addr;
1065	u_char	cdte_datamode;
1066};
1067
1068struct linux_cdrom_subchnl
1069{
1070	u_char	cdsc_format;
1071	u_char	cdsc_audiostatus;
1072	u_char	cdsc_adr:4;
1073	u_char	cdsc_ctrl:4;
1074	u_char	cdsc_trk;
1075	u_char	cdsc_ind;
1076	union linux_cdrom_addr cdsc_absaddr;
1077	union linux_cdrom_addr cdsc_reladdr;
1078};
1079
1080struct l_cdrom_read_audio {
1081	union linux_cdrom_addr addr;
1082	u_char		addr_format;
1083	l_int		nframes;
1084	u_char		*buf;
1085};
1086
1087struct l_dvd_layer {
1088	u_char		book_version:4;
1089	u_char		book_type:4;
1090	u_char		min_rate:4;
1091	u_char		disc_size:4;
1092	u_char		layer_type:4;
1093	u_char		track_path:1;
1094	u_char		nlayers:2;
1095	u_char		track_density:4;
1096	u_char		linear_density:4;
1097	u_char		bca:1;
1098	u_int32_t	start_sector;
1099	u_int32_t	end_sector;
1100	u_int32_t	end_sector_l0;
1101};
1102
1103struct l_dvd_physical {
1104	u_char		type;
1105	u_char		layer_num;
1106	struct l_dvd_layer layer[4];
1107};
1108
1109struct l_dvd_copyright {
1110	u_char		type;
1111	u_char		layer_num;
1112	u_char		cpst;
1113	u_char		rmi;
1114};
1115
1116struct l_dvd_disckey {
1117	u_char		type;
1118	l_uint		agid:2;
1119	u_char		value[2048];
1120};
1121
1122struct l_dvd_bca {
1123	u_char		type;
1124	l_int		len;
1125	u_char		value[188];
1126};
1127
1128struct l_dvd_manufact {
1129	u_char		type;
1130	u_char		layer_num;
1131	l_int		len;
1132	u_char		value[2048];
1133};
1134
1135typedef union {
1136	u_char			type;
1137	struct l_dvd_physical	physical;
1138	struct l_dvd_copyright	copyright;
1139	struct l_dvd_disckey	disckey;
1140	struct l_dvd_bca	bca;
1141	struct l_dvd_manufact	manufact;
1142} l_dvd_struct;
1143
1144typedef u_char l_dvd_key[5];
1145typedef u_char l_dvd_challenge[10];
1146
1147struct l_dvd_lu_send_agid {
1148	u_char		type;
1149	l_uint		agid:2;
1150};
1151
1152struct l_dvd_host_send_challenge {
1153	u_char		type;
1154	l_uint		agid:2;
1155	l_dvd_challenge	chal;
1156};
1157
1158struct l_dvd_send_key {
1159	u_char		type;
1160	l_uint		agid:2;
1161	l_dvd_key	key;
1162};
1163
1164struct l_dvd_lu_send_challenge {
1165	u_char		type;
1166	l_uint		agid:2;
1167	l_dvd_challenge	chal;
1168};
1169
1170struct l_dvd_lu_send_title_key {
1171	u_char		type;
1172	l_uint		agid:2;
1173	l_dvd_key	title_key;
1174	l_int		lba;
1175	l_uint		cpm:1;
1176	l_uint		cp_sec:1;
1177	l_uint		cgms:2;
1178};
1179
1180struct l_dvd_lu_send_asf {
1181	u_char		type;
1182	l_uint		agid:2;
1183	l_uint		asf:1;
1184};
1185
1186struct l_dvd_host_send_rpcstate {
1187	u_char		type;
1188	u_char		pdrc;
1189};
1190
1191struct l_dvd_lu_send_rpcstate {
1192	u_char		type:2;
1193	u_char		vra:3;
1194	u_char		ucca:3;
1195	u_char		region_mask;
1196	u_char		rpc_scheme;
1197};
1198
1199typedef union {
1200	u_char				type;
1201	struct l_dvd_lu_send_agid	lsa;
1202	struct l_dvd_host_send_challenge hsc;
1203	struct l_dvd_send_key		lsk;
1204	struct l_dvd_lu_send_challenge	lsc;
1205	struct l_dvd_send_key		hsk;
1206	struct l_dvd_lu_send_title_key	lstk;
1207	struct l_dvd_lu_send_asf	lsasf;
1208	struct l_dvd_host_send_rpcstate	hrpcs;
1209	struct l_dvd_lu_send_rpcstate	lrpcs;
1210} l_dvd_authinfo;
1211
1212static void
1213bsd_to_linux_msf_lba(u_char af, union msf_lba *bp, union linux_cdrom_addr *lp)
1214{
1215	if (af == CD_LBA_FORMAT)
1216		lp->lba = bp->lba;
1217	else {
1218		lp->msf.minute = bp->msf.minute;
1219		lp->msf.second = bp->msf.second;
1220		lp->msf.frame = bp->msf.frame;
1221	}
1222}
1223
1224static void
1225set_linux_cdrom_addr(union linux_cdrom_addr *addr, int format, int lba)
1226{
1227	if (format == LINUX_CDROM_MSF) {
1228		addr->msf.frame = lba % 75;
1229		lba /= 75;
1230		lba += 2;
1231		addr->msf.second = lba % 60;
1232		addr->msf.minute = lba / 60;
1233	} else
1234		addr->lba = lba;
1235}
1236
1237static int
1238linux_to_bsd_dvd_struct(l_dvd_struct *lp, struct dvd_struct *bp)
1239{
1240	bp->format = lp->type;
1241	switch (bp->format) {
1242	case DVD_STRUCT_PHYSICAL:
1243		if (bp->layer_num >= 4)
1244			return (EINVAL);
1245		bp->layer_num = lp->physical.layer_num;
1246		break;
1247	case DVD_STRUCT_COPYRIGHT:
1248		bp->layer_num = lp->copyright.layer_num;
1249		break;
1250	case DVD_STRUCT_DISCKEY:
1251		bp->agid = lp->disckey.agid;
1252		break;
1253	case DVD_STRUCT_BCA:
1254	case DVD_STRUCT_MANUFACT:
1255		break;
1256	default:
1257		return (EINVAL);
1258	}
1259	return (0);
1260}
1261
1262static int
1263bsd_to_linux_dvd_struct(struct dvd_struct *bp, l_dvd_struct *lp)
1264{
1265	switch (bp->format) {
1266	case DVD_STRUCT_PHYSICAL: {
1267		struct dvd_layer *blp = (struct dvd_layer *)bp->data;
1268		struct l_dvd_layer *llp = &lp->physical.layer[bp->layer_num];
1269		memset(llp, 0, sizeof(*llp));
1270		llp->book_version = blp->book_version;
1271		llp->book_type = blp->book_type;
1272		llp->min_rate = blp->max_rate;
1273		llp->disc_size = blp->disc_size;
1274		llp->layer_type = blp->layer_type;
1275		llp->track_path = blp->track_path;
1276		llp->nlayers = blp->nlayers;
1277		llp->track_density = blp->track_density;
1278		llp->linear_density = blp->linear_density;
1279		llp->bca = blp->bca;
1280		llp->start_sector = blp->start_sector;
1281		llp->end_sector = blp->end_sector;
1282		llp->end_sector_l0 = blp->end_sector_l0;
1283		break;
1284	}
1285	case DVD_STRUCT_COPYRIGHT:
1286		lp->copyright.cpst = bp->cpst;
1287		lp->copyright.rmi = bp->rmi;
1288		break;
1289	case DVD_STRUCT_DISCKEY:
1290		memcpy(lp->disckey.value, bp->data, sizeof(lp->disckey.value));
1291		break;
1292	case DVD_STRUCT_BCA:
1293		lp->bca.len = bp->length;
1294		memcpy(lp->bca.value, bp->data, sizeof(lp->bca.value));
1295		break;
1296	case DVD_STRUCT_MANUFACT:
1297		lp->manufact.len = bp->length;
1298		memcpy(lp->manufact.value, bp->data,
1299		    sizeof(lp->manufact.value));
1300		/* lp->manufact.layer_num is unused in linux (redhat 7.0) */
1301		break;
1302	default:
1303		return (EINVAL);
1304	}
1305	return (0);
1306}
1307
1308static int
1309linux_to_bsd_dvd_authinfo(l_dvd_authinfo *lp, int *bcode,
1310    struct dvd_authinfo *bp)
1311{
1312	switch (lp->type) {
1313	case LINUX_DVD_LU_SEND_AGID:
1314		*bcode = DVDIOCREPORTKEY;
1315		bp->format = DVD_REPORT_AGID;
1316		bp->agid = lp->lsa.agid;
1317		break;
1318	case LINUX_DVD_HOST_SEND_CHALLENGE:
1319		*bcode = DVDIOCSENDKEY;
1320		bp->format = DVD_SEND_CHALLENGE;
1321		bp->agid = lp->hsc.agid;
1322		memcpy(bp->keychal, lp->hsc.chal, 10);
1323		break;
1324	case LINUX_DVD_LU_SEND_KEY1:
1325		*bcode = DVDIOCREPORTKEY;
1326		bp->format = DVD_REPORT_KEY1;
1327		bp->agid = lp->lsk.agid;
1328		break;
1329	case LINUX_DVD_LU_SEND_CHALLENGE:
1330		*bcode = DVDIOCREPORTKEY;
1331		bp->format = DVD_REPORT_CHALLENGE;
1332		bp->agid = lp->lsc.agid;
1333		break;
1334	case LINUX_DVD_HOST_SEND_KEY2:
1335		*bcode = DVDIOCSENDKEY;
1336		bp->format = DVD_SEND_KEY2;
1337		bp->agid = lp->hsk.agid;
1338		memcpy(bp->keychal, lp->hsk.key, 5);
1339		break;
1340	case LINUX_DVD_LU_SEND_TITLE_KEY:
1341		*bcode = DVDIOCREPORTKEY;
1342		bp->format = DVD_REPORT_TITLE_KEY;
1343		bp->agid = lp->lstk.agid;
1344		bp->lba = lp->lstk.lba;
1345		break;
1346	case LINUX_DVD_LU_SEND_ASF:
1347		*bcode = DVDIOCREPORTKEY;
1348		bp->format = DVD_REPORT_ASF;
1349		bp->agid = lp->lsasf.agid;
1350		break;
1351	case LINUX_DVD_INVALIDATE_AGID:
1352		*bcode = DVDIOCREPORTKEY;
1353		bp->format = DVD_INVALIDATE_AGID;
1354		bp->agid = lp->lsa.agid;
1355		break;
1356	case LINUX_DVD_LU_SEND_RPC_STATE:
1357		*bcode = DVDIOCREPORTKEY;
1358		bp->format = DVD_REPORT_RPC;
1359		break;
1360	case LINUX_DVD_HOST_SEND_RPC_STATE:
1361		*bcode = DVDIOCSENDKEY;
1362		bp->format = DVD_SEND_RPC;
1363		bp->region = lp->hrpcs.pdrc;
1364		break;
1365	default:
1366		return (EINVAL);
1367	}
1368	return (0);
1369}
1370
1371static int
1372bsd_to_linux_dvd_authinfo(struct dvd_authinfo *bp, l_dvd_authinfo *lp)
1373{
1374	switch (lp->type) {
1375	case LINUX_DVD_LU_SEND_AGID:
1376		lp->lsa.agid = bp->agid;
1377		break;
1378	case LINUX_DVD_HOST_SEND_CHALLENGE:
1379		lp->type = LINUX_DVD_LU_SEND_KEY1;
1380		break;
1381	case LINUX_DVD_LU_SEND_KEY1:
1382		memcpy(lp->lsk.key, bp->keychal, sizeof(lp->lsk.key));
1383		break;
1384	case LINUX_DVD_LU_SEND_CHALLENGE:
1385		memcpy(lp->lsc.chal, bp->keychal, sizeof(lp->lsc.chal));
1386		break;
1387	case LINUX_DVD_HOST_SEND_KEY2:
1388		lp->type = LINUX_DVD_AUTH_ESTABLISHED;
1389		break;
1390	case LINUX_DVD_LU_SEND_TITLE_KEY:
1391		memcpy(lp->lstk.title_key, bp->keychal,
1392		    sizeof(lp->lstk.title_key));
1393		lp->lstk.cpm = bp->cpm;
1394		lp->lstk.cp_sec = bp->cp_sec;
1395		lp->lstk.cgms = bp->cgms;
1396		break;
1397	case LINUX_DVD_LU_SEND_ASF:
1398		lp->lsasf.asf = bp->asf;
1399		break;
1400	case LINUX_DVD_INVALIDATE_AGID:
1401		break;
1402	case LINUX_DVD_LU_SEND_RPC_STATE:
1403		lp->lrpcs.type = bp->reg_type;
1404		lp->lrpcs.vra = bp->vend_rsts;
1405		lp->lrpcs.ucca = bp->user_rsts;
1406		lp->lrpcs.region_mask = bp->region;
1407		lp->lrpcs.rpc_scheme = bp->rpc_scheme;
1408		break;
1409	case LINUX_DVD_HOST_SEND_RPC_STATE:
1410		break;
1411	default:
1412		return (EINVAL);
1413	}
1414	return (0);
1415}
1416
1417static int
1418linux_ioctl_cdrom(struct thread *td, struct linux_ioctl_args *args)
1419{
1420	struct file *fp;
1421	int error;
1422
1423	if ((error = fget(td, args->fd, &fp)) != 0)
1424		return (error);
1425	switch (args->cmd & 0xffff) {
1426
1427	case LINUX_CDROMPAUSE:
1428		args->cmd = CDIOCPAUSE;
1429		error = (ioctl(td, (struct ioctl_args *)args));
1430		break;
1431
1432	case LINUX_CDROMRESUME:
1433		args->cmd = CDIOCRESUME;
1434		error = (ioctl(td, (struct ioctl_args *)args));
1435		break;
1436
1437	case LINUX_CDROMPLAYMSF:
1438		args->cmd = CDIOCPLAYMSF;
1439		error = (ioctl(td, (struct ioctl_args *)args));
1440		break;
1441
1442	case LINUX_CDROMPLAYTRKIND:
1443		args->cmd = CDIOCPLAYTRACKS;
1444		error = (ioctl(td, (struct ioctl_args *)args));
1445		break;
1446
1447	case LINUX_CDROMREADTOCHDR: {
1448		struct ioc_toc_header th;
1449		struct linux_cdrom_tochdr lth;
1450		error = fo_ioctl(fp, CDIOREADTOCHEADER, (caddr_t)&th,
1451		    td->td_ucred, td);
1452		if (!error) {
1453			lth.cdth_trk0 = th.starting_track;
1454			lth.cdth_trk1 = th.ending_track;
1455			copyout(&lth, (void *)args->arg, sizeof(lth));
1456		}
1457		break;
1458	}
1459
1460	case LINUX_CDROMREADTOCENTRY: {
1461		struct linux_cdrom_tocentry lte;
1462		struct ioc_read_toc_single_entry irtse;
1463
1464		error = copyin((void *)args->arg, &lte, sizeof(lte));
1465		if (error)
1466			break;
1467		irtse.address_format = lte.cdte_format;
1468		irtse.track = lte.cdte_track;
1469		error = fo_ioctl(fp, CDIOREADTOCENTRY, (caddr_t)&irtse,
1470		    td->td_ucred, td);
1471		if (!error) {
1472			lte.cdte_ctrl = irtse.entry.control;
1473			lte.cdte_adr = irtse.entry.addr_type;
1474			bsd_to_linux_msf_lba(irtse.address_format,
1475			    &irtse.entry.addr, &lte.cdte_addr);
1476			error = copyout(&lte, (void *)args->arg, sizeof(lte));
1477		}
1478		break;
1479	}
1480
1481	case LINUX_CDROMSTOP:
1482		args->cmd = CDIOCSTOP;
1483		error = (ioctl(td, (struct ioctl_args *)args));
1484		break;
1485
1486	case LINUX_CDROMSTART:
1487		args->cmd = CDIOCSTART;
1488		error = (ioctl(td, (struct ioctl_args *)args));
1489		break;
1490
1491	case LINUX_CDROMEJECT:
1492		args->cmd = CDIOCEJECT;
1493		error = (ioctl(td, (struct ioctl_args *)args));
1494		break;
1495
1496	/* LINUX_CDROMVOLCTRL */
1497
1498	case LINUX_CDROMSUBCHNL: {
1499		struct linux_cdrom_subchnl sc;
1500		struct ioc_read_subchannel bsdsc;
1501		struct cd_sub_channel_info bsdinfo;
1502
1503		bsdsc.address_format = CD_LBA_FORMAT;
1504		bsdsc.data_format = CD_CURRENT_POSITION;
1505		bsdsc.track = 0;
1506		bsdsc.data_len = sizeof(bsdinfo);
1507		bsdsc.data = &bsdinfo;
1508		error = fo_ioctl(fp, CDIOCREADSUBCHANNEL_SYSSPACE,
1509		    (caddr_t)&bsdsc, td->td_ucred, td);
1510		if (error)
1511			break;
1512		error = copyin((void *)args->arg, &sc, sizeof(sc));
1513		if (error)
1514			break;
1515		sc.cdsc_audiostatus = bsdinfo.header.audio_status;
1516		sc.cdsc_adr = bsdinfo.what.position.addr_type;
1517		sc.cdsc_ctrl = bsdinfo.what.position.control;
1518		sc.cdsc_trk = bsdinfo.what.position.track_number;
1519		sc.cdsc_ind = bsdinfo.what.position.index_number;
1520		set_linux_cdrom_addr(&sc.cdsc_absaddr, sc.cdsc_format,
1521		    bsdinfo.what.position.absaddr.lba);
1522		set_linux_cdrom_addr(&sc.cdsc_reladdr, sc.cdsc_format,
1523		    bsdinfo.what.position.reladdr.lba);
1524		error = copyout(&sc, (void *)args->arg, sizeof(sc));
1525		break;
1526	}
1527
1528	/* LINUX_CDROMREADMODE2 */
1529	/* LINUX_CDROMREADMODE1 */
1530	/* LINUX_CDROMREADAUDIO */
1531	/* LINUX_CDROMEJECT_SW */
1532	/* LINUX_CDROMMULTISESSION */
1533	/* LINUX_CDROM_GET_UPC */
1534
1535	case LINUX_CDROMRESET:
1536		args->cmd = CDIOCRESET;
1537		error = (ioctl(td, (struct ioctl_args *)args));
1538		break;
1539
1540	/* LINUX_CDROMVOLREAD */
1541	/* LINUX_CDROMREADRAW */
1542	/* LINUX_CDROMREADCOOKED */
1543	/* LINUX_CDROMSEEK */
1544	/* LINUX_CDROMPLAYBLK */
1545	/* LINUX_CDROMREADALL */
1546	/* LINUX_CDROMCLOSETRAY */
1547	/* LINUX_CDROMLOADFROMSLOT */
1548	/* LINUX_CDROMGETSPINDOWN */
1549	/* LINUX_CDROMSETSPINDOWN */
1550	/* LINUX_CDROM_SET_OPTIONS */
1551	/* LINUX_CDROM_CLEAR_OPTIONS */
1552	/* LINUX_CDROM_SELECT_SPEED */
1553	/* LINUX_CDROM_SELECT_DISC */
1554	/* LINUX_CDROM_MEDIA_CHANGED */
1555	/* LINUX_CDROM_DRIVE_STATUS */
1556	/* LINUX_CDROM_DISC_STATUS */
1557	/* LINUX_CDROM_CHANGER_NSLOTS */
1558	/* LINUX_CDROM_LOCKDOOR */
1559	/* LINUX_CDROM_DEBUG */
1560	/* LINUX_CDROM_GET_CAPABILITY */
1561	/* LINUX_CDROMAUDIOBUFSIZ */
1562
1563	case LINUX_DVD_READ_STRUCT: {
1564		l_dvd_struct *lds;
1565		struct dvd_struct *bds;
1566
1567		lds = malloc(sizeof(*lds), M_LINUX, M_WAITOK);
1568		bds = malloc(sizeof(*bds), M_LINUX, M_WAITOK);
1569		error = copyin((void *)args->arg, lds, sizeof(*lds));
1570		if (error)
1571			goto out;
1572		error = linux_to_bsd_dvd_struct(lds, bds);
1573		if (error)
1574			goto out;
1575		error = fo_ioctl(fp, DVDIOCREADSTRUCTURE, (caddr_t)bds,
1576		    td->td_ucred, td);
1577		if (error)
1578			goto out;
1579		error = bsd_to_linux_dvd_struct(bds, lds);
1580		if (error)
1581			goto out;
1582		error = copyout(lds, (void *)args->arg, sizeof(*lds));
1583	out:
1584		free(bds, M_LINUX);
1585		free(lds, M_LINUX);
1586		break;
1587	}
1588
1589	/* LINUX_DVD_WRITE_STRUCT */
1590
1591	case LINUX_DVD_AUTH: {
1592		l_dvd_authinfo lda;
1593		struct dvd_authinfo bda;
1594		int bcode;
1595
1596		error = copyin((void *)args->arg, &lda, sizeof(lda));
1597		if (error)
1598			break;
1599		error = linux_to_bsd_dvd_authinfo(&lda, &bcode, &bda);
1600		if (error)
1601			break;
1602		error = fo_ioctl(fp, bcode, (caddr_t)&bda, td->td_ucred,
1603		    td);
1604		if (error) {
1605			if (lda.type == LINUX_DVD_HOST_SEND_KEY2) {
1606				lda.type = LINUX_DVD_AUTH_FAILURE;
1607				copyout(&lda, (void *)args->arg, sizeof(lda));
1608			}
1609			break;
1610		}
1611		error = bsd_to_linux_dvd_authinfo(&bda, &lda);
1612		if (error)
1613			break;
1614		error = copyout(&lda, (void *)args->arg, sizeof(lda));
1615		break;
1616	}
1617
1618	case LINUX_SCSI_GET_BUS_NUMBER:
1619	case LINUX_SCSI_GET_IDLUN:
1620		error = linux_ioctl_sg(td, args);
1621		break;
1622
1623	/* LINUX_CDROM_SEND_PACKET */
1624	/* LINUX_CDROM_NEXT_WRITABLE */
1625	/* LINUX_CDROM_LAST_WRITTEN */
1626
1627	default:
1628		error = ENOIOCTL;
1629		break;
1630	}
1631
1632	fdrop(fp, td);
1633	return (error);
1634}
1635
1636static int
1637linux_ioctl_vfat(struct thread *td, struct linux_ioctl_args *args)
1638{
1639
1640	return (ENOTTY);
1641}
1642
1643/*
1644 * Sound related ioctls
1645 */
1646
1647struct linux_mixer_info {
1648	char	id[16];
1649	char	name[32];
1650	int	modify_counter;
1651	int	fillers[10];
1652};
1653
1654struct linux_old_mixer_info {
1655	char	id[16];
1656	char	name[32];
1657};
1658
1659static u_int32_t dirbits[4] = { IOC_VOID, IOC_IN, IOC_OUT, IOC_INOUT };
1660
1661#define	SETDIR(c)	(((c) & ~IOC_DIRMASK) | dirbits[args->cmd >> 30])
1662
1663static int
1664linux_ioctl_sound(struct thread *td, struct linux_ioctl_args *args)
1665{
1666
1667	switch (args->cmd & 0xffff) {
1668
1669	case LINUX_SOUND_MIXER_WRITE_VOLUME:
1670		args->cmd = SETDIR(SOUND_MIXER_WRITE_VOLUME);
1671		return (ioctl(td, (struct ioctl_args *)args));
1672
1673	case LINUX_SOUND_MIXER_WRITE_BASS:
1674		args->cmd = SETDIR(SOUND_MIXER_WRITE_BASS);
1675		return (ioctl(td, (struct ioctl_args *)args));
1676
1677	case LINUX_SOUND_MIXER_WRITE_TREBLE:
1678		args->cmd = SETDIR(SOUND_MIXER_WRITE_TREBLE);
1679		return (ioctl(td, (struct ioctl_args *)args));
1680
1681	case LINUX_SOUND_MIXER_WRITE_SYNTH:
1682		args->cmd = SETDIR(SOUND_MIXER_WRITE_SYNTH);
1683		return (ioctl(td, (struct ioctl_args *)args));
1684
1685	case LINUX_SOUND_MIXER_WRITE_PCM:
1686		args->cmd = SETDIR(SOUND_MIXER_WRITE_PCM);
1687		return (ioctl(td, (struct ioctl_args *)args));
1688
1689	case LINUX_SOUND_MIXER_WRITE_SPEAKER:
1690		args->cmd = SETDIR(SOUND_MIXER_WRITE_SPEAKER);
1691		return (ioctl(td, (struct ioctl_args *)args));
1692
1693	case LINUX_SOUND_MIXER_WRITE_LINE:
1694		args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE);
1695		return (ioctl(td, (struct ioctl_args *)args));
1696
1697	case LINUX_SOUND_MIXER_WRITE_MIC:
1698		args->cmd = SETDIR(SOUND_MIXER_WRITE_MIC);
1699		return (ioctl(td, (struct ioctl_args *)args));
1700
1701	case LINUX_SOUND_MIXER_WRITE_CD:
1702		args->cmd = SETDIR(SOUND_MIXER_WRITE_CD);
1703		return (ioctl(td, (struct ioctl_args *)args));
1704
1705	case LINUX_SOUND_MIXER_WRITE_IMIX:
1706		args->cmd = SETDIR(SOUND_MIXER_WRITE_IMIX);
1707		return (ioctl(td, (struct ioctl_args *)args));
1708
1709	case LINUX_SOUND_MIXER_WRITE_ALTPCM:
1710		args->cmd = SETDIR(SOUND_MIXER_WRITE_ALTPCM);
1711		return (ioctl(td, (struct ioctl_args *)args));
1712
1713	case LINUX_SOUND_MIXER_WRITE_RECLEV:
1714		args->cmd = SETDIR(SOUND_MIXER_WRITE_RECLEV);
1715		return (ioctl(td, (struct ioctl_args *)args));
1716
1717	case LINUX_SOUND_MIXER_WRITE_IGAIN:
1718		args->cmd = SETDIR(SOUND_MIXER_WRITE_IGAIN);
1719		return (ioctl(td, (struct ioctl_args *)args));
1720
1721	case LINUX_SOUND_MIXER_WRITE_OGAIN:
1722		args->cmd = SETDIR(SOUND_MIXER_WRITE_OGAIN);
1723		return (ioctl(td, (struct ioctl_args *)args));
1724
1725	case LINUX_SOUND_MIXER_WRITE_LINE1:
1726		args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE1);
1727		return (ioctl(td, (struct ioctl_args *)args));
1728
1729	case LINUX_SOUND_MIXER_WRITE_LINE2:
1730		args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE2);
1731		return (ioctl(td, (struct ioctl_args *)args));
1732
1733	case LINUX_SOUND_MIXER_WRITE_LINE3:
1734		args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE3);
1735		return (ioctl(td, (struct ioctl_args *)args));
1736
1737	case LINUX_SOUND_MIXER_INFO: {
1738		/* Key on encoded length */
1739		switch ((args->cmd >> 16) & 0x1fff) {
1740		case 0x005c: {	/* SOUND_MIXER_INFO */
1741			struct linux_mixer_info info;
1742			bzero(&info, sizeof(info));
1743			strncpy(info.id, "OSS", sizeof(info.id) - 1);
1744			strncpy(info.name, "FreeBSD OSS Mixer", sizeof(info.name) - 1);
1745			copyout(&info, (void *)args->arg, sizeof(info));
1746			break;
1747		}
1748		case 0x0030: {	/* SOUND_OLD_MIXER_INFO */
1749			struct linux_old_mixer_info info;
1750			bzero(&info, sizeof(info));
1751			strncpy(info.id, "OSS", sizeof(info.id) - 1);
1752			strncpy(info.name, "FreeBSD OSS Mixer", sizeof(info.name) - 1);
1753			copyout(&info, (void *)args->arg, sizeof(info));
1754			break;
1755		}
1756		default:
1757			return (ENOIOCTL);
1758		}
1759		break;
1760	}
1761
1762	case LINUX_OSS_GETVERSION: {
1763		int version = linux_get_oss_version(td);
1764		return (copyout(&version, (void *)args->arg, sizeof(int)));
1765	}
1766
1767	case LINUX_SOUND_MIXER_READ_STEREODEVS:
1768		args->cmd = SOUND_MIXER_READ_STEREODEVS;
1769		return (ioctl(td, (struct ioctl_args *)args));
1770
1771	case LINUX_SOUND_MIXER_READ_RECMASK:
1772		args->cmd = SOUND_MIXER_READ_RECMASK;
1773		return (ioctl(td, (struct ioctl_args *)args));
1774
1775	case LINUX_SOUND_MIXER_READ_DEVMASK:
1776		args->cmd = SOUND_MIXER_READ_DEVMASK;
1777		return (ioctl(td, (struct ioctl_args *)args));
1778
1779	case LINUX_SOUND_MIXER_WRITE_RECSRC:
1780		args->cmd = SETDIR(SOUND_MIXER_WRITE_RECSRC);
1781		return (ioctl(td, (struct ioctl_args *)args));
1782
1783	case LINUX_SNDCTL_DSP_RESET:
1784		args->cmd = SNDCTL_DSP_RESET;
1785		return (ioctl(td, (struct ioctl_args *)args));
1786
1787	case LINUX_SNDCTL_DSP_SYNC:
1788		args->cmd = SNDCTL_DSP_SYNC;
1789		return (ioctl(td, (struct ioctl_args *)args));
1790
1791	case LINUX_SNDCTL_DSP_SPEED:
1792		args->cmd = SNDCTL_DSP_SPEED;
1793		return (ioctl(td, (struct ioctl_args *)args));
1794
1795	case LINUX_SNDCTL_DSP_STEREO:
1796		args->cmd = SNDCTL_DSP_STEREO;
1797		return (ioctl(td, (struct ioctl_args *)args));
1798
1799	case LINUX_SNDCTL_DSP_GETBLKSIZE: /* LINUX_SNDCTL_DSP_SETBLKSIZE */
1800		args->cmd = SNDCTL_DSP_GETBLKSIZE;
1801		return (ioctl(td, (struct ioctl_args *)args));
1802
1803	case LINUX_SNDCTL_DSP_SETFMT:
1804		args->cmd = SNDCTL_DSP_SETFMT;
1805		return (ioctl(td, (struct ioctl_args *)args));
1806
1807	case LINUX_SOUND_PCM_WRITE_CHANNELS:
1808		args->cmd = SOUND_PCM_WRITE_CHANNELS;
1809		return (ioctl(td, (struct ioctl_args *)args));
1810
1811	case LINUX_SOUND_PCM_WRITE_FILTER:
1812		args->cmd = SOUND_PCM_WRITE_FILTER;
1813		return (ioctl(td, (struct ioctl_args *)args));
1814
1815	case LINUX_SNDCTL_DSP_POST:
1816		args->cmd = SNDCTL_DSP_POST;
1817		return (ioctl(td, (struct ioctl_args *)args));
1818
1819	case LINUX_SNDCTL_DSP_SUBDIVIDE:
1820		args->cmd = SNDCTL_DSP_SUBDIVIDE;
1821		return (ioctl(td, (struct ioctl_args *)args));
1822
1823	case LINUX_SNDCTL_DSP_SETFRAGMENT:
1824		args->cmd = SNDCTL_DSP_SETFRAGMENT;
1825		return (ioctl(td, (struct ioctl_args *)args));
1826
1827	case LINUX_SNDCTL_DSP_GETFMTS:
1828		args->cmd = SNDCTL_DSP_GETFMTS;
1829		return (ioctl(td, (struct ioctl_args *)args));
1830
1831	case LINUX_SNDCTL_DSP_GETOSPACE:
1832		args->cmd = SNDCTL_DSP_GETOSPACE;
1833		return (ioctl(td, (struct ioctl_args *)args));
1834
1835	case LINUX_SNDCTL_DSP_GETISPACE:
1836		args->cmd = SNDCTL_DSP_GETISPACE;
1837		return (ioctl(td, (struct ioctl_args *)args));
1838
1839	case LINUX_SNDCTL_DSP_NONBLOCK:
1840		args->cmd = SNDCTL_DSP_NONBLOCK;
1841		return (ioctl(td, (struct ioctl_args *)args));
1842
1843	case LINUX_SNDCTL_DSP_GETCAPS:
1844		args->cmd = SNDCTL_DSP_GETCAPS;
1845		return (ioctl(td, (struct ioctl_args *)args));
1846
1847	case LINUX_SNDCTL_DSP_SETTRIGGER: /* LINUX_SNDCTL_GETTRIGGER */
1848		args->cmd = SNDCTL_DSP_SETTRIGGER;
1849		return (ioctl(td, (struct ioctl_args *)args));
1850
1851	case LINUX_SNDCTL_DSP_GETIPTR:
1852		args->cmd = SNDCTL_DSP_GETIPTR;
1853		return (ioctl(td, (struct ioctl_args *)args));
1854
1855	case LINUX_SNDCTL_DSP_GETOPTR:
1856		args->cmd = SNDCTL_DSP_GETOPTR;
1857		return (ioctl(td, (struct ioctl_args *)args));
1858
1859	case LINUX_SNDCTL_DSP_SETDUPLEX:
1860		args->cmd = SNDCTL_DSP_SETDUPLEX;
1861		return (ioctl(td, (struct ioctl_args *)args));
1862
1863	case LINUX_SNDCTL_DSP_GETODELAY:
1864		args->cmd = SNDCTL_DSP_GETODELAY;
1865		return (ioctl(td, (struct ioctl_args *)args));
1866
1867	case LINUX_SNDCTL_SEQ_RESET:
1868		args->cmd = SNDCTL_SEQ_RESET;
1869		return (ioctl(td, (struct ioctl_args *)args));
1870
1871	case LINUX_SNDCTL_SEQ_SYNC:
1872		args->cmd = SNDCTL_SEQ_SYNC;
1873		return (ioctl(td, (struct ioctl_args *)args));
1874
1875	case LINUX_SNDCTL_SYNTH_INFO:
1876		args->cmd = SNDCTL_SYNTH_INFO;
1877		return (ioctl(td, (struct ioctl_args *)args));
1878
1879	case LINUX_SNDCTL_SEQ_CTRLRATE:
1880		args->cmd = SNDCTL_SEQ_CTRLRATE;
1881		return (ioctl(td, (struct ioctl_args *)args));
1882
1883	case LINUX_SNDCTL_SEQ_GETOUTCOUNT:
1884		args->cmd = SNDCTL_SEQ_GETOUTCOUNT;
1885		return (ioctl(td, (struct ioctl_args *)args));
1886
1887	case LINUX_SNDCTL_SEQ_GETINCOUNT:
1888		args->cmd = SNDCTL_SEQ_GETINCOUNT;
1889		return (ioctl(td, (struct ioctl_args *)args));
1890
1891	case LINUX_SNDCTL_SEQ_PERCMODE:
1892		args->cmd = SNDCTL_SEQ_PERCMODE;
1893		return (ioctl(td, (struct ioctl_args *)args));
1894
1895	case LINUX_SNDCTL_FM_LOAD_INSTR:
1896		args->cmd = SNDCTL_FM_LOAD_INSTR;
1897		return (ioctl(td, (struct ioctl_args *)args));
1898
1899	case LINUX_SNDCTL_SEQ_TESTMIDI:
1900		args->cmd = SNDCTL_SEQ_TESTMIDI;
1901		return (ioctl(td, (struct ioctl_args *)args));
1902
1903	case LINUX_SNDCTL_SEQ_RESETSAMPLES:
1904		args->cmd = SNDCTL_SEQ_RESETSAMPLES;
1905		return (ioctl(td, (struct ioctl_args *)args));
1906
1907	case LINUX_SNDCTL_SEQ_NRSYNTHS:
1908		args->cmd = SNDCTL_SEQ_NRSYNTHS;
1909		return (ioctl(td, (struct ioctl_args *)args));
1910
1911	case LINUX_SNDCTL_SEQ_NRMIDIS:
1912		args->cmd = SNDCTL_SEQ_NRMIDIS;
1913		return (ioctl(td, (struct ioctl_args *)args));
1914
1915	case LINUX_SNDCTL_MIDI_INFO:
1916		args->cmd = SNDCTL_MIDI_INFO;
1917		return (ioctl(td, (struct ioctl_args *)args));
1918
1919	case LINUX_SNDCTL_SEQ_TRESHOLD:
1920		args->cmd = SNDCTL_SEQ_TRESHOLD;
1921		return (ioctl(td, (struct ioctl_args *)args));
1922
1923	case LINUX_SNDCTL_SYNTH_MEMAVL:
1924		args->cmd = SNDCTL_SYNTH_MEMAVL;
1925		return (ioctl(td, (struct ioctl_args *)args));
1926
1927	}
1928
1929	return (ENOIOCTL);
1930}
1931
1932/*
1933 * Console related ioctls
1934 */
1935
1936#define ISSIGVALID(sig)		((sig) > 0 && (sig) < NSIG)
1937
1938static int
1939linux_ioctl_console(struct thread *td, struct linux_ioctl_args *args)
1940{
1941	struct file *fp;
1942	int error;
1943
1944	if ((error = fget(td, args->fd, &fp)) != 0)
1945		return (error);
1946	switch (args->cmd & 0xffff) {
1947
1948	case LINUX_KIOCSOUND:
1949		args->cmd = KIOCSOUND;
1950		error = (ioctl(td, (struct ioctl_args *)args));
1951		break;
1952
1953	case LINUX_KDMKTONE:
1954		args->cmd = KDMKTONE;
1955		error = (ioctl(td, (struct ioctl_args *)args));
1956		break;
1957
1958	case LINUX_KDGETLED:
1959		args->cmd = KDGETLED;
1960		error = (ioctl(td, (struct ioctl_args *)args));
1961		break;
1962
1963	case LINUX_KDSETLED:
1964		args->cmd = KDSETLED;
1965		error = (ioctl(td, (struct ioctl_args *)args));
1966		break;
1967
1968	case LINUX_KDSETMODE:
1969		args->cmd = KDSETMODE;
1970		error = (ioctl(td, (struct ioctl_args *)args));
1971		break;
1972
1973	case LINUX_KDGETMODE:
1974		args->cmd = KDGETMODE;
1975		error = (ioctl(td, (struct ioctl_args *)args));
1976		break;
1977
1978	case LINUX_KDGKBMODE:
1979		args->cmd = KDGKBMODE;
1980		error = (ioctl(td, (struct ioctl_args *)args));
1981		break;
1982
1983	case LINUX_KDSKBMODE: {
1984		int kbdmode;
1985		switch (args->arg) {
1986		case LINUX_KBD_RAW:
1987			kbdmode = K_RAW;
1988			break;
1989		case LINUX_KBD_XLATE:
1990			kbdmode = K_XLATE;
1991			break;
1992		case LINUX_KBD_MEDIUMRAW:
1993			kbdmode = K_RAW;
1994			break;
1995		default:
1996			fdrop(fp, td);
1997			return (EINVAL);
1998		}
1999		error = (fo_ioctl(fp, KDSKBMODE, (caddr_t)&kbdmode,
2000		    td->td_ucred, td));
2001		break;
2002	}
2003
2004	case LINUX_VT_OPENQRY:
2005		args->cmd = VT_OPENQRY;
2006		error = (ioctl(td, (struct ioctl_args *)args));
2007		break;
2008
2009	case LINUX_VT_GETMODE:
2010		args->cmd = VT_GETMODE;
2011		error = (ioctl(td, (struct ioctl_args *)args));
2012		break;
2013
2014	case LINUX_VT_SETMODE: {
2015		struct vt_mode mode;
2016		if ((error = copyin((void *)args->arg, &mode, sizeof(mode))))
2017			break;
2018		if (!ISSIGVALID(mode.frsig) && ISSIGVALID(mode.acqsig))
2019			mode.frsig = mode.acqsig;
2020		if ((error = copyout(&mode, (void *)args->arg, sizeof(mode))))
2021			break;
2022		args->cmd = VT_SETMODE;
2023		error = (ioctl(td, (struct ioctl_args *)args));
2024		break;
2025	}
2026
2027	case LINUX_VT_GETSTATE:
2028		args->cmd = VT_GETACTIVE;
2029		error = (ioctl(td, (struct ioctl_args *)args));
2030		break;
2031
2032	case LINUX_VT_RELDISP:
2033		args->cmd = VT_RELDISP;
2034		error = (ioctl(td, (struct ioctl_args *)args));
2035		break;
2036
2037	case LINUX_VT_ACTIVATE:
2038		args->cmd = VT_ACTIVATE;
2039		error = (ioctl(td, (struct ioctl_args *)args));
2040		break;
2041
2042	case LINUX_VT_WAITACTIVE:
2043		args->cmd = VT_WAITACTIVE;
2044		error = (ioctl(td, (struct ioctl_args *)args));
2045		break;
2046
2047	default:
2048		error = ENOIOCTL;
2049		break;
2050	}
2051
2052	fdrop(fp, td);
2053	return (error);
2054}
2055
2056/*
2057 * Criteria for interface name translation
2058 */
2059#define IFP_IS_ETH(ifp) (ifp->if_type == IFT_ETHER)
2060
2061/*
2062 * Interface function used by linprocfs (at the time of writing). It's not
2063 * used by the Linuxulator itself.
2064 */
2065int
2066linux_ifname(struct ifnet *ifp, char *buffer, size_t buflen)
2067{
2068	struct ifnet *ifscan;
2069	int ethno;
2070
2071	IFNET_RLOCK_ASSERT();
2072
2073	/* Short-circuit non ethernet interfaces */
2074	if (!IFP_IS_ETH(ifp))
2075		return (strlcpy(buffer, ifp->if_xname, buflen));
2076
2077	/* Determine the (relative) unit number for ethernet interfaces */
2078	ethno = 0;
2079	TAILQ_FOREACH(ifscan, &V_ifnet, if_link) {
2080		if (ifscan == ifp)
2081			return (snprintf(buffer, buflen, "eth%d", ethno));
2082		if (IFP_IS_ETH(ifscan))
2083			ethno++;
2084	}
2085
2086	return (0);
2087}
2088
2089/*
2090 * Translate a Linux interface name to a FreeBSD interface name,
2091 * and return the associated ifnet structure
2092 * bsdname and lxname need to be least IFNAMSIZ bytes long, but
2093 * can point to the same buffer.
2094 */
2095
2096static struct ifnet *
2097ifname_linux_to_bsd(struct thread *td, const char *lxname, char *bsdname)
2098{
2099	struct ifnet *ifp;
2100	int len, unit;
2101	char *ep;
2102	int is_eth, index;
2103
2104	for (len = 0; len < LINUX_IFNAMSIZ; ++len)
2105		if (!isalpha(lxname[len]))
2106			break;
2107	if (len == 0 || len == LINUX_IFNAMSIZ)
2108		return (NULL);
2109	unit = (int)strtoul(lxname + len, &ep, 10);
2110	if (ep == NULL || ep == lxname + len || ep >= lxname + LINUX_IFNAMSIZ)
2111		return (NULL);
2112	index = 0;
2113	is_eth = (len == 3 && !strncmp(lxname, "eth", len)) ? 1 : 0;
2114	CURVNET_SET(TD_TO_VNET(td));
2115	IFNET_RLOCK();
2116	TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
2117		/*
2118		 * Allow Linux programs to use FreeBSD names. Don't presume
2119		 * we never have an interface named "eth", so don't make
2120		 * the test optional based on is_eth.
2121		 */
2122		if (strncmp(ifp->if_xname, lxname, LINUX_IFNAMSIZ) == 0)
2123			break;
2124		if (is_eth && IFP_IS_ETH(ifp) && unit == index++)
2125			break;
2126	}
2127	IFNET_RUNLOCK();
2128	CURVNET_RESTORE();
2129	if (ifp != NULL)
2130		strlcpy(bsdname, ifp->if_xname, IFNAMSIZ);
2131	return (ifp);
2132}
2133
2134/*
2135 * Implement the SIOCGIFCONF ioctl
2136 */
2137
2138static int
2139linux_ifconf(struct thread *td, struct ifconf *uifc)
2140{
2141#ifdef COMPAT_LINUX32
2142	struct l_ifconf ifc;
2143#else
2144	struct ifconf ifc;
2145#endif
2146	struct l_ifreq ifr;
2147	struct ifnet *ifp;
2148	struct ifaddr *ifa;
2149	struct sbuf *sb;
2150	int error, ethno, full = 0, valid_len, max_len;
2151
2152	error = copyin(uifc, &ifc, sizeof(ifc));
2153	if (error != 0)
2154		return (error);
2155
2156	max_len = MAXPHYS - 1;
2157
2158	CURVNET_SET(TD_TO_VNET(td));
2159	/* handle the 'request buffer size' case */
2160	if (ifc.ifc_buf == PTROUT(NULL)) {
2161		ifc.ifc_len = 0;
2162		IFNET_RLOCK();
2163		TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
2164			TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
2165				struct sockaddr *sa = ifa->ifa_addr;
2166				if (sa->sa_family == AF_INET)
2167					ifc.ifc_len += sizeof(ifr);
2168			}
2169		}
2170		IFNET_RUNLOCK();
2171		error = copyout(&ifc, uifc, sizeof(ifc));
2172		CURVNET_RESTORE();
2173		return (error);
2174	}
2175
2176	if (ifc.ifc_len <= 0) {
2177		CURVNET_RESTORE();
2178		return (EINVAL);
2179	}
2180
2181again:
2182	/* Keep track of eth interfaces */
2183	ethno = 0;
2184	if (ifc.ifc_len <= max_len) {
2185		max_len = ifc.ifc_len;
2186		full = 1;
2187	}
2188	sb = sbuf_new(NULL, NULL, max_len + 1, SBUF_FIXEDLEN);
2189	max_len = 0;
2190	valid_len = 0;
2191
2192	/* Return all AF_INET addresses of all interfaces */
2193	IFNET_RLOCK();
2194	TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
2195		int addrs = 0;
2196
2197		bzero(&ifr, sizeof(ifr));
2198		if (IFP_IS_ETH(ifp))
2199			snprintf(ifr.ifr_name, LINUX_IFNAMSIZ, "eth%d",
2200			    ethno++);
2201		else
2202			strlcpy(ifr.ifr_name, ifp->if_xname, LINUX_IFNAMSIZ);
2203
2204		/* Walk the address list */
2205		TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
2206			struct sockaddr *sa = ifa->ifa_addr;
2207
2208			if (sa->sa_family == AF_INET) {
2209				ifr.ifr_addr.sa_family = LINUX_AF_INET;
2210				memcpy(ifr.ifr_addr.sa_data, sa->sa_data,
2211				    sizeof(ifr.ifr_addr.sa_data));
2212				sbuf_bcat(sb, &ifr, sizeof(ifr));
2213				max_len += sizeof(ifr);
2214				addrs++;
2215			}
2216
2217			if (!sbuf_overflowed(sb))
2218				valid_len = sbuf_len(sb);
2219		}
2220		if (addrs == 0) {
2221			bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
2222			sbuf_bcat(sb, &ifr, sizeof(ifr));
2223			max_len += sizeof(ifr);
2224
2225			if (!sbuf_overflowed(sb))
2226				valid_len = sbuf_len(sb);
2227		}
2228	}
2229	IFNET_RUNLOCK();
2230
2231	if (valid_len != max_len && !full) {
2232		sbuf_delete(sb);
2233		goto again;
2234	}
2235
2236	ifc.ifc_len = valid_len;
2237	sbuf_finish(sb);
2238	memcpy(PTRIN(ifc.ifc_buf), sbuf_data(sb), ifc.ifc_len);
2239	error = copyout(&ifc, uifc, sizeof(ifc));
2240	sbuf_delete(sb);
2241	CURVNET_RESTORE();
2242
2243	return (error);
2244}
2245
2246static int
2247linux_gifflags(struct thread *td, struct ifnet *ifp, struct l_ifreq *ifr)
2248{
2249	l_short flags;
2250
2251	flags = (ifp->if_flags | ifp->if_drv_flags) & 0xffff;
2252	/* these flags have no Linux equivalent */
2253	flags &= ~(IFF_SMART|IFF_DRV_OACTIVE|IFF_SIMPLEX|
2254	    IFF_LINK0|IFF_LINK1|IFF_LINK2);
2255	/* Linux' multicast flag is in a different bit */
2256	if (flags & IFF_MULTICAST) {
2257		flags &= ~IFF_MULTICAST;
2258		flags |= 0x1000;
2259	}
2260
2261	return (copyout(&flags, &ifr->ifr_flags, sizeof(flags)));
2262}
2263
2264#define ARPHRD_ETHER	1
2265#define ARPHRD_LOOPBACK	772
2266
2267static int
2268linux_gifhwaddr(struct ifnet *ifp, struct l_ifreq *ifr)
2269{
2270	struct ifaddr *ifa;
2271	struct sockaddr_dl *sdl;
2272	struct l_sockaddr lsa;
2273
2274	if (ifp->if_type == IFT_LOOP) {
2275		bzero(&lsa, sizeof(lsa));
2276		lsa.sa_family = ARPHRD_LOOPBACK;
2277		return (copyout(&lsa, &ifr->ifr_hwaddr, sizeof(lsa)));
2278	}
2279
2280	if (ifp->if_type != IFT_ETHER)
2281		return (ENOENT);
2282
2283	TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
2284		sdl = (struct sockaddr_dl*)ifa->ifa_addr;
2285		if (sdl != NULL && (sdl->sdl_family == AF_LINK) &&
2286		    (sdl->sdl_type == IFT_ETHER)) {
2287			bzero(&lsa, sizeof(lsa));
2288			lsa.sa_family = ARPHRD_ETHER;
2289			bcopy(LLADDR(sdl), lsa.sa_data, LINUX_IFHWADDRLEN);
2290			return (copyout(&lsa, &ifr->ifr_hwaddr, sizeof(lsa)));
2291		}
2292	}
2293
2294	return (ENOENT);
2295}
2296
2297
2298 /*
2299* If we fault in bsd_to_linux_ifreq() then we will fault when we call
2300* the native ioctl().  Thus, we don't really need to check the return
2301* value of this function.
2302*/
2303static int
2304bsd_to_linux_ifreq(struct ifreq *arg)
2305{
2306	struct ifreq ifr;
2307	size_t ifr_len = sizeof(struct ifreq);
2308	int error;
2309
2310	if ((error = copyin(arg, &ifr, ifr_len)))
2311		return (error);
2312
2313	*(u_short *)&ifr.ifr_addr = ifr.ifr_addr.sa_family;
2314
2315	error = copyout(&ifr, arg, ifr_len);
2316
2317	return (error);
2318}
2319
2320/*
2321 * Socket related ioctls
2322 */
2323
2324static int
2325linux_ioctl_socket(struct thread *td, struct linux_ioctl_args *args)
2326{
2327	char lifname[LINUX_IFNAMSIZ], ifname[IFNAMSIZ];
2328	struct ifnet *ifp;
2329	struct file *fp;
2330	int error, type;
2331
2332	ifp = NULL;
2333	error = 0;
2334
2335	if ((error = fget(td, args->fd, &fp)) != 0)
2336		return (error);
2337	type = fp->f_type;
2338	fdrop(fp, td);
2339	if (type != DTYPE_SOCKET) {
2340		/* not a socket - probably a tap / vmnet device */
2341		switch (args->cmd) {
2342		case LINUX_SIOCGIFADDR:
2343		case LINUX_SIOCSIFADDR:
2344		case LINUX_SIOCGIFFLAGS:
2345			return (linux_ioctl_special(td, args));
2346		default:
2347			return (ENOIOCTL);
2348		}
2349	}
2350
2351	switch (args->cmd & 0xffff) {
2352
2353	case LINUX_FIOGETOWN:
2354	case LINUX_FIOSETOWN:
2355	case LINUX_SIOCADDMULTI:
2356	case LINUX_SIOCATMARK:
2357	case LINUX_SIOCDELMULTI:
2358	case LINUX_SIOCGIFCONF:
2359	case LINUX_SIOCGPGRP:
2360	case LINUX_SIOCSPGRP:
2361	case LINUX_SIOCGIFCOUNT:
2362		/* these ioctls don't take an interface name */
2363#ifdef DEBUG
2364		printf("%s(): ioctl %d\n", __func__,
2365		    args->cmd & 0xffff);
2366#endif
2367		break;
2368
2369	case LINUX_SIOCGIFFLAGS:
2370	case LINUX_SIOCGIFADDR:
2371	case LINUX_SIOCSIFADDR:
2372	case LINUX_SIOCGIFDSTADDR:
2373	case LINUX_SIOCGIFBRDADDR:
2374	case LINUX_SIOCGIFNETMASK:
2375	case LINUX_SIOCSIFNETMASK:
2376	case LINUX_SIOCGIFMTU:
2377	case LINUX_SIOCSIFMTU:
2378	case LINUX_SIOCSIFNAME:
2379	case LINUX_SIOCGIFHWADDR:
2380	case LINUX_SIOCSIFHWADDR:
2381	case LINUX_SIOCDEVPRIVATE:
2382	case LINUX_SIOCDEVPRIVATE+1:
2383	case LINUX_SIOCGIFINDEX:
2384		/* copy in the interface name and translate it. */
2385		error = copyin((void *)args->arg, lifname, LINUX_IFNAMSIZ);
2386		if (error != 0)
2387			return (error);
2388#ifdef DEBUG
2389		printf("%s(): ioctl %d on %.*s\n", __func__,
2390		    args->cmd & 0xffff, LINUX_IFNAMSIZ, lifname);
2391#endif
2392		ifp = ifname_linux_to_bsd(td, lifname, ifname);
2393		if (ifp == NULL)
2394			return (EINVAL);
2395		/*
2396		 * We need to copy it back out in case we pass the
2397		 * request on to our native ioctl(), which will expect
2398		 * the ifreq to be in user space and have the correct
2399		 * interface name.
2400		 */
2401		error = copyout(ifname, (void *)args->arg, IFNAMSIZ);
2402		if (error != 0)
2403			return (error);
2404#ifdef DEBUG
2405		printf("%s(): %s translated to %s\n", __func__,
2406		    lifname, ifname);
2407#endif
2408		break;
2409
2410	default:
2411		return (ENOIOCTL);
2412	}
2413
2414	switch (args->cmd & 0xffff) {
2415
2416	case LINUX_FIOSETOWN:
2417		args->cmd = FIOSETOWN;
2418		error = ioctl(td, (struct ioctl_args *)args);
2419		break;
2420
2421	case LINUX_SIOCSPGRP:
2422		args->cmd = SIOCSPGRP;
2423		error = ioctl(td, (struct ioctl_args *)args);
2424		break;
2425
2426	case LINUX_FIOGETOWN:
2427		args->cmd = FIOGETOWN;
2428		error = ioctl(td, (struct ioctl_args *)args);
2429		break;
2430
2431	case LINUX_SIOCGPGRP:
2432		args->cmd = SIOCGPGRP;
2433		error = ioctl(td, (struct ioctl_args *)args);
2434		break;
2435
2436	case LINUX_SIOCATMARK:
2437		args->cmd = SIOCATMARK;
2438		error = ioctl(td, (struct ioctl_args *)args);
2439		break;
2440
2441	/* LINUX_SIOCGSTAMP */
2442
2443	case LINUX_SIOCGIFCONF:
2444		error = linux_ifconf(td, (struct ifconf *)args->arg);
2445		break;
2446
2447	case LINUX_SIOCGIFFLAGS:
2448		args->cmd = SIOCGIFFLAGS;
2449		error = linux_gifflags(td, ifp, (struct l_ifreq *)args->arg);
2450		break;
2451
2452	case LINUX_SIOCGIFADDR:
2453		args->cmd = SIOCGIFADDR;
2454		error = ioctl(td, (struct ioctl_args *)args);
2455		bsd_to_linux_ifreq((struct ifreq *)args->arg);
2456		break;
2457
2458	case LINUX_SIOCSIFADDR:
2459		/* XXX probably doesn't work, included for completeness */
2460		args->cmd = SIOCSIFADDR;
2461		error = ioctl(td, (struct ioctl_args *)args);
2462		break;
2463
2464	case LINUX_SIOCGIFDSTADDR:
2465		args->cmd = SIOCGIFDSTADDR;
2466		error = ioctl(td, (struct ioctl_args *)args);
2467		bsd_to_linux_ifreq((struct ifreq *)args->arg);
2468		break;
2469
2470	case LINUX_SIOCGIFBRDADDR:
2471		args->cmd = SIOCGIFBRDADDR;
2472		error = ioctl(td, (struct ioctl_args *)args);
2473		bsd_to_linux_ifreq((struct ifreq *)args->arg);
2474		break;
2475
2476	case LINUX_SIOCGIFNETMASK:
2477		args->cmd = SIOCGIFNETMASK;
2478		error = ioctl(td, (struct ioctl_args *)args);
2479		bsd_to_linux_ifreq((struct ifreq *)args->arg);
2480		break;
2481
2482	case LINUX_SIOCSIFNETMASK:
2483		error = ENOIOCTL;
2484		break;
2485
2486	case LINUX_SIOCGIFMTU:
2487		args->cmd = SIOCGIFMTU;
2488		error = ioctl(td, (struct ioctl_args *)args);
2489		break;
2490
2491	case LINUX_SIOCSIFMTU:
2492		args->cmd = SIOCSIFMTU;
2493		error = ioctl(td, (struct ioctl_args *)args);
2494		break;
2495
2496	case LINUX_SIOCSIFNAME:
2497		error = ENOIOCTL;
2498		break;
2499
2500	case LINUX_SIOCGIFHWADDR:
2501		error = linux_gifhwaddr(ifp, (struct l_ifreq *)args->arg);
2502		break;
2503
2504	case LINUX_SIOCSIFHWADDR:
2505		error = ENOIOCTL;
2506		break;
2507
2508	case LINUX_SIOCADDMULTI:
2509		args->cmd = SIOCADDMULTI;
2510		error = ioctl(td, (struct ioctl_args *)args);
2511		break;
2512
2513	case LINUX_SIOCDELMULTI:
2514		args->cmd = SIOCDELMULTI;
2515		error = ioctl(td, (struct ioctl_args *)args);
2516		break;
2517
2518	case LINUX_SIOCGIFINDEX:
2519		args->cmd = SIOCGIFINDEX;
2520		error = ioctl(td, (struct ioctl_args *)args);
2521		break;
2522
2523	case LINUX_SIOCGIFCOUNT:
2524		error = 0;
2525		break;
2526
2527	/*
2528	 * XXX This is slightly bogus, but these ioctls are currently
2529	 * XXX only used by the aironet (if_an) network driver.
2530	 */
2531	case LINUX_SIOCDEVPRIVATE:
2532		args->cmd = SIOCGPRIVATE_0;
2533		error = ioctl(td, (struct ioctl_args *)args);
2534		break;
2535
2536	case LINUX_SIOCDEVPRIVATE+1:
2537		args->cmd = SIOCGPRIVATE_1;
2538		error = ioctl(td, (struct ioctl_args *)args);
2539		break;
2540	}
2541
2542	if (ifp != NULL)
2543		/* restore the original interface name */
2544		copyout(lifname, (void *)args->arg, LINUX_IFNAMSIZ);
2545
2546#ifdef DEBUG
2547	printf("%s(): returning %d\n", __func__, error);
2548#endif
2549	return (error);
2550}
2551
2552/*
2553 * Device private ioctl handler
2554 */
2555static int
2556linux_ioctl_private(struct thread *td, struct linux_ioctl_args *args)
2557{
2558	struct file *fp;
2559	int error, type;
2560
2561	if ((error = fget(td, args->fd, &fp)) != 0)
2562		return (error);
2563	type = fp->f_type;
2564	fdrop(fp, td);
2565	if (type == DTYPE_SOCKET)
2566		return (linux_ioctl_socket(td, args));
2567	return (ENOIOCTL);
2568}
2569
2570/*
2571 * DRM ioctl handler (sys/dev/drm)
2572 */
2573static int
2574linux_ioctl_drm(struct thread *td, struct linux_ioctl_args *args)
2575{
2576	args->cmd = SETDIR(args->cmd);
2577	return ioctl(td, (struct ioctl_args *)args);
2578}
2579
2580static int
2581linux_ioctl_sg(struct thread *td, struct linux_ioctl_args *args)
2582{
2583	struct file *fp;
2584	u_long cmd;
2585	int error;
2586
2587	if ((error = fget(td, args->fd, &fp)) != 0) {
2588		printf("sg_linux_ioctl: fget returned %d\n", error);
2589		return (error);
2590	}
2591	cmd = args->cmd;
2592
2593	error = (fo_ioctl(fp, cmd, (caddr_t)args->arg, td->td_ucred, td));
2594	fdrop(fp, td);
2595	return (error);
2596}
2597
2598/*
2599 * Video4Linux (V4L) ioctl handler
2600 */
2601static int
2602linux_to_bsd_v4l_tuner(struct l_video_tuner *lvt, struct video_tuner *vt)
2603{
2604	vt->tuner = lvt->tuner;
2605	strlcpy(vt->name, lvt->name, LINUX_VIDEO_TUNER_NAME_SIZE);
2606	vt->rangelow = lvt->rangelow;	/* possible long size conversion */
2607	vt->rangehigh = lvt->rangehigh;	/* possible long size conversion */
2608	vt->flags = lvt->flags;
2609	vt->mode = lvt->mode;
2610	vt->signal = lvt->signal;
2611	return (0);
2612}
2613
2614static int
2615bsd_to_linux_v4l_tuner(struct video_tuner *vt, struct l_video_tuner *lvt)
2616{
2617	lvt->tuner = vt->tuner;
2618	strlcpy(lvt->name, vt->name, LINUX_VIDEO_TUNER_NAME_SIZE);
2619	lvt->rangelow = vt->rangelow;	/* possible long size conversion */
2620	lvt->rangehigh = vt->rangehigh;	/* possible long size conversion */
2621	lvt->flags = vt->flags;
2622	lvt->mode = vt->mode;
2623	lvt->signal = vt->signal;
2624	return (0);
2625}
2626
2627static int
2628linux_to_bsd_v4l_clip(struct l_video_clip *lvc, struct video_clip *vc)
2629{
2630	vc->x = lvc->x;
2631	vc->y = lvc->y;
2632	vc->width = lvc->width;
2633	vc->height = lvc->height;
2634	vc->next = PTRIN(lvc->next);	/* possible pointer size conversion */
2635	return (0);
2636}
2637
2638static int
2639linux_to_bsd_v4l_window(struct l_video_window *lvw, struct video_window *vw)
2640{
2641	vw->x = lvw->x;
2642	vw->y = lvw->y;
2643	vw->width = lvw->width;
2644	vw->height = lvw->height;
2645	vw->chromakey = lvw->chromakey;
2646	vw->flags = lvw->flags;
2647	vw->clips = PTRIN(lvw->clips);	/* possible pointer size conversion */
2648	vw->clipcount = lvw->clipcount;
2649	return (0);
2650}
2651
2652static int
2653bsd_to_linux_v4l_window(struct video_window *vw, struct l_video_window *lvw)
2654{
2655	lvw->x = vw->x;
2656	lvw->y = vw->y;
2657	lvw->width = vw->width;
2658	lvw->height = vw->height;
2659	lvw->chromakey = vw->chromakey;
2660	lvw->flags = vw->flags;
2661	lvw->clips = PTROUT(vw->clips);	/* possible pointer size conversion */
2662	lvw->clipcount = vw->clipcount;
2663	return (0);
2664}
2665
2666static int
2667linux_to_bsd_v4l_buffer(struct l_video_buffer *lvb, struct video_buffer *vb)
2668{
2669	vb->base = PTRIN(lvb->base);	/* possible pointer size conversion */
2670	vb->height = lvb->height;
2671	vb->width = lvb->width;
2672	vb->depth = lvb->depth;
2673	vb->bytesperline = lvb->bytesperline;
2674	return (0);
2675}
2676
2677static int
2678bsd_to_linux_v4l_buffer(struct video_buffer *vb, struct l_video_buffer *lvb)
2679{
2680	lvb->base = PTROUT(vb->base);	/* possible pointer size conversion */
2681	lvb->height = vb->height;
2682	lvb->width = vb->width;
2683	lvb->depth = vb->depth;
2684	lvb->bytesperline = vb->bytesperline;
2685	return (0);
2686}
2687
2688static int
2689linux_to_bsd_v4l_code(struct l_video_code *lvc, struct video_code *vc)
2690{
2691	strlcpy(vc->loadwhat, lvc->loadwhat, LINUX_VIDEO_CODE_LOADWHAT_SIZE);
2692	vc->datasize = lvc->datasize;
2693	vc->data = PTRIN(lvc->data);	/* possible pointer size conversion */
2694	return (0);
2695}
2696
2697static int
2698linux_v4l_clip_copy(void *lvc, struct video_clip **ppvc)
2699{
2700	int error;
2701	struct video_clip vclip;
2702	struct l_video_clip l_vclip;
2703
2704	error = copyin(lvc, &l_vclip, sizeof(l_vclip));
2705	if (error) return (error);
2706	linux_to_bsd_v4l_clip(&l_vclip, &vclip);
2707	/* XXX: If there can be no concurrency: s/M_NOWAIT/M_WAITOK/ */
2708	if ((*ppvc = malloc(sizeof(**ppvc), M_LINUX, M_NOWAIT)) == NULL)
2709		return (ENOMEM);    /* XXX: linux has no ENOMEM here */
2710	memcpy(&vclip, *ppvc, sizeof(vclip));
2711	(*ppvc)->next = NULL;
2712	return (0);
2713}
2714
2715static int
2716linux_v4l_cliplist_free(struct video_window *vw)
2717{
2718	struct video_clip **ppvc;
2719	struct video_clip **ppvc_next;
2720
2721	for (ppvc = &(vw->clips); *ppvc != NULL; ppvc = ppvc_next) {
2722		ppvc_next = &((*ppvc)->next);
2723		free(*ppvc, M_LINUX);
2724	}
2725	return (0);
2726}
2727
2728static int
2729linux_v4l_cliplist_copy(struct l_video_window *lvw, struct video_window *vw)
2730{
2731	int error;
2732	int clipcount;
2733	void *plvc;
2734	struct video_clip **ppvc;
2735
2736	/*
2737	 * XXX: The cliplist is used to pass in a list of clipping
2738	 *	rectangles or, if clipcount == VIDEO_CLIP_BITMAP, a
2739	 *	clipping bitmap.  Some Linux apps, however, appear to
2740	 *	leave cliplist and clips uninitialized.  In any case,
2741	 *	the cliplist is not used by pwc(4), at the time of
2742	 *	writing, FreeBSD's only V4L driver.  When a driver
2743	 *	that uses the cliplist is developed, this code may
2744	 *	need re-examiniation.
2745	 */
2746	error = 0;
2747	clipcount = vw->clipcount;
2748	if (clipcount == VIDEO_CLIP_BITMAP) {
2749		/*
2750		 * In this case, the pointer (clips) is overloaded
2751		 * to be a "void *" to a bitmap, therefore there
2752		 * is no struct video_clip to copy now.
2753		 */
2754	} else if (clipcount > 0 && clipcount <= 16384) {
2755		/*
2756		 * Clips points to list of clip rectangles, so
2757		 * copy the list.
2758		 *
2759		 * XXX: Upper limit of 16384 was used here to try to
2760		 *	avoid cases when clipcount and clips pointer
2761		 *	are uninitialized and therefore have high random
2762		 *	values, as is the case in the Linux Skype
2763		 *	application.  The value 16384 was chosen as that
2764		 *	is what is used in the Linux stradis(4) MPEG
2765		 *	decoder driver, the only place we found an
2766		 *	example of cliplist use.
2767		 */
2768		plvc = PTRIN(lvw->clips);
2769		ppvc = &(vw->clips);
2770		while (clipcount-- > 0) {
2771			if (plvc == 0)
2772				error = EFAULT;
2773			if (!error)
2774				error = linux_v4l_clip_copy(plvc, ppvc);
2775			if (error) {
2776				linux_v4l_cliplist_free(vw);
2777				break;
2778			}
2779			ppvc = &((*ppvc)->next);
2780		        plvc = PTRIN(((struct l_video_clip *) plvc)->next);
2781		}
2782	} else {
2783		/*
2784		 * clipcount == 0 or negative (but not VIDEO_CLIP_BITMAP)
2785		 * Force cliplist to null.
2786		 */
2787		vw->clipcount = 0;
2788		vw->clips = NULL;
2789	}
2790	return (error);
2791}
2792
2793static int
2794linux_ioctl_v4l(struct thread *td, struct linux_ioctl_args *args)
2795{
2796	struct file *fp;
2797	int error;
2798	struct video_tuner vtun;
2799	struct video_window vwin;
2800	struct video_buffer vbuf;
2801	struct video_code vcode;
2802	struct l_video_tuner l_vtun;
2803	struct l_video_window l_vwin;
2804	struct l_video_buffer l_vbuf;
2805	struct l_video_code l_vcode;
2806
2807	switch (args->cmd & 0xffff) {
2808	case LINUX_VIDIOCGCAP:		args->cmd = VIDIOCGCAP; break;
2809	case LINUX_VIDIOCGCHAN:		args->cmd = VIDIOCGCHAN; break;
2810	case LINUX_VIDIOCSCHAN:		args->cmd = VIDIOCSCHAN; break;
2811
2812	case LINUX_VIDIOCGTUNER:
2813		if ((error = fget(td, args->fd, &fp)) != 0)
2814			return (error);
2815		error = fo_ioctl(fp, VIDIOCGTUNER, &vtun, td->td_ucred, td);
2816		if (!error) {
2817			bsd_to_linux_v4l_tuner(&vtun, &l_vtun);
2818			error = copyout(&l_vtun, (void *) args->arg,
2819			    sizeof(l_vtun));
2820		}
2821		fdrop(fp, td);
2822		return (error);
2823
2824	case LINUX_VIDIOCSTUNER:
2825		if ((error = fget(td, args->fd, &fp)) != 0)
2826			return (error);
2827		error = copyin((void *) args->arg, &l_vtun, sizeof(l_vtun));
2828		if (error) {
2829			fdrop(fp, td);
2830			return (error);
2831		}
2832		linux_to_bsd_v4l_tuner(&l_vtun, &vtun);
2833		error = fo_ioctl(fp, VIDIOCSMICROCODE, &vtun, td->td_ucred, td);
2834		fdrop(fp, td);
2835		return (error);
2836
2837	case LINUX_VIDIOCGPICT:		args->cmd = VIDIOCGPICT; break;
2838	case LINUX_VIDIOCSPICT:		args->cmd = VIDIOCSPICT; break;
2839	case LINUX_VIDIOCCAPTURE:	args->cmd = VIDIOCCAPTURE; break;
2840
2841	case LINUX_VIDIOCGWIN:
2842		if ((error = fget(td, args->fd, &fp)) != 0)
2843			return (error);
2844		error = fo_ioctl(fp, VIDIOCGWIN, &vwin, td->td_ucred, td);
2845		if (!error) {
2846			bsd_to_linux_v4l_window(&vwin, &l_vwin);
2847			error = copyout(&l_vwin, (void *) args->arg,
2848			    sizeof(l_vwin));
2849		}
2850		fdrop(fp, td);
2851		return (error);
2852
2853	case LINUX_VIDIOCSWIN:
2854		if ((error = fget(td, args->fd, &fp)) != 0)
2855			return (error);
2856		error = copyin((void *) args->arg, &l_vwin, sizeof(l_vwin));
2857		if (error) {
2858			fdrop(fp, td);
2859			return (error);
2860		}
2861		linux_to_bsd_v4l_window(&l_vwin, &vwin);
2862		error = linux_v4l_cliplist_copy(&l_vwin, &vwin);
2863		if (error) {
2864			fdrop(fp, td);
2865			return (error);
2866		}
2867		error = fo_ioctl(fp, VIDIOCSWIN, &vwin, td->td_ucred, td);
2868		fdrop(fp, td);
2869		linux_v4l_cliplist_free(&vwin);
2870		return (error);
2871
2872	case LINUX_VIDIOCGFBUF:
2873		if ((error = fget(td, args->fd, &fp)) != 0)
2874			return (error);
2875		error = fo_ioctl(fp, VIDIOCGFBUF, &vbuf, td->td_ucred, td);
2876		if (!error) {
2877			bsd_to_linux_v4l_buffer(&vbuf, &l_vbuf);
2878			error = copyout(&l_vbuf, (void *) args->arg,
2879			    sizeof(l_vbuf));
2880		}
2881		fdrop(fp, td);
2882		return (error);
2883
2884	case LINUX_VIDIOCSFBUF:
2885		if ((error = fget(td, args->fd, &fp)) != 0)
2886			return (error);
2887		error = copyin((void *) args->arg, &l_vbuf, sizeof(l_vbuf));
2888		if (error) {
2889			fdrop(fp, td);
2890			return (error);
2891		}
2892		linux_to_bsd_v4l_buffer(&l_vbuf, &vbuf);
2893		error = fo_ioctl(fp, VIDIOCSFBUF, &vbuf, td->td_ucred, td);
2894		fdrop(fp, td);
2895		return (error);
2896
2897	case LINUX_VIDIOCKEY:		args->cmd = VIDIOCKEY; break;
2898	case LINUX_VIDIOCGFREQ:		args->cmd = VIDIOCGFREQ; break;
2899	case LINUX_VIDIOCSFREQ:		args->cmd = VIDIOCSFREQ; break;
2900	case LINUX_VIDIOCGAUDIO:	args->cmd = VIDIOCGAUDIO; break;
2901	case LINUX_VIDIOCSAUDIO:	args->cmd = VIDIOCSAUDIO; break;
2902	case LINUX_VIDIOCSYNC:		args->cmd = VIDIOCSYNC; break;
2903	case LINUX_VIDIOCMCAPTURE:	args->cmd = VIDIOCMCAPTURE; break;
2904	case LINUX_VIDIOCGMBUF:		args->cmd = VIDIOCGMBUF; break;
2905	case LINUX_VIDIOCGUNIT:		args->cmd = VIDIOCGUNIT; break;
2906	case LINUX_VIDIOCGCAPTURE:	args->cmd = VIDIOCGCAPTURE; break;
2907	case LINUX_VIDIOCSCAPTURE:	args->cmd = VIDIOCSCAPTURE; break;
2908	case LINUX_VIDIOCSPLAYMODE:	args->cmd = VIDIOCSPLAYMODE; break;
2909	case LINUX_VIDIOCSWRITEMODE:	args->cmd = VIDIOCSWRITEMODE; break;
2910	case LINUX_VIDIOCGPLAYINFO:	args->cmd = VIDIOCGPLAYINFO; break;
2911
2912	case LINUX_VIDIOCSMICROCODE:
2913		if ((error = fget(td, args->fd, &fp)) != 0)
2914			return (error);
2915		error = copyin((void *) args->arg, &l_vcode, sizeof(l_vcode));
2916		if (error) {
2917			fdrop(fp, td);
2918			return (error);
2919		}
2920		linux_to_bsd_v4l_code(&l_vcode, &vcode);
2921		error = fo_ioctl(fp, VIDIOCSTUNER, &vcode, td->td_ucred, td);
2922		fdrop(fp, td);
2923		return (error);
2924
2925	case LINUX_VIDIOCGVBIFMT:	args->cmd = VIDIOCGVBIFMT; break;
2926	case LINUX_VIDIOCSVBIFMT:	args->cmd = VIDIOCSVBIFMT; break;
2927	default:			return (ENOIOCTL);
2928	}
2929
2930	error = ioctl(td, (struct ioctl_args *)args);
2931	return (error);
2932}
2933
2934/*
2935 * Special ioctl handler
2936 */
2937static int
2938linux_ioctl_special(struct thread *td, struct linux_ioctl_args *args)
2939{
2940	int error;
2941
2942	switch (args->cmd) {
2943	case LINUX_SIOCGIFADDR:
2944		args->cmd = SIOCGIFADDR;
2945		error = ioctl(td, (struct ioctl_args *)args);
2946		break;
2947	case LINUX_SIOCSIFADDR:
2948		args->cmd = SIOCSIFADDR;
2949		error = ioctl(td, (struct ioctl_args *)args);
2950		break;
2951	case LINUX_SIOCGIFFLAGS:
2952		args->cmd = SIOCGIFFLAGS;
2953		error = ioctl(td, (struct ioctl_args *)args);
2954		break;
2955	default:
2956		error = ENOIOCTL;
2957	}
2958
2959	return (error);
2960}
2961
2962/*
2963 * main ioctl syscall function
2964 */
2965
2966int
2967linux_ioctl(struct thread *td, struct linux_ioctl_args *args)
2968{
2969	struct file *fp;
2970	struct handler_element *he;
2971	int error, cmd;
2972
2973#ifdef DEBUG
2974	if (ldebug(ioctl))
2975		printf(ARGS(ioctl, "%d, %04lx, *"), args->fd,
2976		    (unsigned long)args->cmd);
2977#endif
2978
2979	if ((error = fget(td, args->fd, &fp)) != 0)
2980		return (error);
2981	if ((fp->f_flag & (FREAD|FWRITE)) == 0) {
2982		fdrop(fp, td);
2983		return (EBADF);
2984	}
2985
2986	/* Iterate over the ioctl handlers */
2987	cmd = args->cmd & 0xffff;
2988	sx_slock(&linux_ioctl_sx);
2989	mtx_lock(&Giant);
2990	TAILQ_FOREACH(he, &handlers, list) {
2991		if (cmd >= he->low && cmd <= he->high) {
2992			error = (*he->func)(td, args);
2993			if (error != ENOIOCTL) {
2994				mtx_unlock(&Giant);
2995				sx_sunlock(&linux_ioctl_sx);
2996				fdrop(fp, td);
2997				return (error);
2998			}
2999		}
3000	}
3001	mtx_unlock(&Giant);
3002	sx_sunlock(&linux_ioctl_sx);
3003	fdrop(fp, td);
3004
3005	linux_msg(td, "ioctl fd=%d, cmd=0x%x ('%c',%d) is not implemented",
3006	    args->fd, (int)(args->cmd & 0xffff),
3007	    (int)(args->cmd & 0xff00) >> 8, (int)(args->cmd & 0xff));
3008
3009	return (EINVAL);
3010}
3011
3012int
3013linux_ioctl_register_handler(struct linux_ioctl_handler *h)
3014{
3015	struct handler_element *he, *cur;
3016
3017	if (h == NULL || h->func == NULL)
3018		return (EINVAL);
3019
3020	/*
3021	 * Reuse the element if the handler is already on the list, otherwise
3022	 * create a new element.
3023	 */
3024	sx_xlock(&linux_ioctl_sx);
3025	TAILQ_FOREACH(he, &handlers, list) {
3026		if (he->func == h->func)
3027			break;
3028	}
3029	if (he == NULL) {
3030		he = malloc(sizeof(*he),
3031		    M_LINUX, M_WAITOK);
3032		he->func = h->func;
3033	} else
3034		TAILQ_REMOVE(&handlers, he, list);
3035
3036	/* Initialize range information. */
3037	he->low = h->low;
3038	he->high = h->high;
3039	he->span = h->high - h->low + 1;
3040
3041	/* Add the element to the list, sorted on span. */
3042	TAILQ_FOREACH(cur, &handlers, list) {
3043		if (cur->span > he->span) {
3044			TAILQ_INSERT_BEFORE(cur, he, list);
3045			sx_xunlock(&linux_ioctl_sx);
3046			return (0);
3047		}
3048	}
3049	TAILQ_INSERT_TAIL(&handlers, he, list);
3050	sx_xunlock(&linux_ioctl_sx);
3051
3052	return (0);
3053}
3054
3055int
3056linux_ioctl_unregister_handler(struct linux_ioctl_handler *h)
3057{
3058	struct handler_element *he;
3059
3060	if (h == NULL || h->func == NULL)
3061		return (EINVAL);
3062
3063	sx_xlock(&linux_ioctl_sx);
3064	TAILQ_FOREACH(he, &handlers, list) {
3065		if (he->func == h->func) {
3066			TAILQ_REMOVE(&handlers, he, list);
3067			sx_xunlock(&linux_ioctl_sx);
3068			free(he, M_LINUX);
3069			return (0);
3070		}
3071	}
3072	sx_xunlock(&linux_ioctl_sx);
3073
3074	return (EINVAL);
3075}
3076