Add a MNTK_ flag to the mount structure allowing a VFS to specify that
[dragonfly.git] / sys / emulation / linux / linux_ioctl.c
1 /*
2  * Copyright (c) 1994-1995 Søren Schmidt
3  * Copyright (c) 2004 Simon 'corecode' Schubert
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer
11  *    in this position and unchanged.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software withough specific prior written permission
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  *
29  * $FreeBSD: src/sys/compat/linux/linux_ioctl.c,v 1.55.2.11 2003/05/01 20:16:09 anholt Exp $
30  * $DragonFly: src/sys/emulation/linux/linux_ioctl.c,v 1.24 2007/05/17 21:07:13 dillon Exp $
31  */
32
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/sysproto.h>
36 #include <sys/cdio.h>
37 #include <sys/consio.h>
38 #include <sys/ctype.h>
39 #include <sys/diskslice.h>
40 #include <sys/fcntl.h>
41 #include <sys/file.h>
42 #include <sys/filedesc.h>
43 #include <sys/filio.h>
44 #include <sys/ioccom.h>
45 #include <sys/kbio.h>
46 #include <sys/kernel.h>
47 #include <sys/linker_set.h>
48 #include <sys/malloc.h>
49 #include <sys/mapped_ioctl.h>
50 #include <sys/proc.h>
51 #include <sys/socket.h>
52 #include <sys/sockio.h>
53 #include <sys/soundcard.h>
54 #include <sys/tty.h>
55 #include <sys/uio.h>
56 #include <net/if.h>
57 #include <net/if_dl.h>
58 #include <net/if_types.h>
59 #include <sys/file2.h>
60
61 #include <arch_linux/linux.h>
62 #include <arch_linux/linux_proto.h>
63
64 #include "linux_ioctl.h"
65 #include "linux_mib.h"
66 #include "linux_util.h"
67
68
69 static int
70 linux_ioctl_BLKGETSIZE32(struct file *fp, u_long cmd, u_long ocmd,
71                          caddr_t data, struct ucred *cred)
72 {
73         struct partinfo dpart;
74         u_int32_t value;
75         int error;
76
77         error = fo_ioctl(fp, DIOCGPART, (caddr_t)&dpart, cred);
78         if (error)
79                 return (error);
80         value = dpart.media_blocks;     /* 64->32 */
81         bcopy(&value, data, sizeof(value));
82         return (0);
83 }
84
85
86 /*
87  * termio related ioctls
88  */
89
90 struct linux_termio {
91         unsigned short c_iflag;
92         unsigned short c_oflag;
93         unsigned short c_cflag;
94         unsigned short c_lflag;
95         unsigned char c_line;
96         unsigned char c_cc[LINUX_NCC];
97 };
98
99 struct linux_termios {
100         unsigned int c_iflag;
101         unsigned int c_oflag;
102         unsigned int c_cflag;
103         unsigned int c_lflag;
104         unsigned char c_line;
105         unsigned char c_cc[LINUX_NCCS];
106 };
107
108 struct linux_winsize {
109         unsigned short ws_row, ws_col;
110         unsigned short ws_xpixel, ws_ypixel;
111 };
112
113 static struct speedtab sptab[] = {
114         { B0, LINUX_B0 }, { B50, LINUX_B50 },
115         { B75, LINUX_B75 }, { B110, LINUX_B110 },
116         { B134, LINUX_B134 }, { B150, LINUX_B150 },
117         { B200, LINUX_B200 }, { B300, LINUX_B300 },
118         { B600, LINUX_B600 }, { B1200, LINUX_B1200 },
119         { B1800, LINUX_B1800 }, { B2400, LINUX_B2400 },
120         { B4800, LINUX_B4800 }, { B9600, LINUX_B9600 },
121         { B19200, LINUX_B19200 }, { B38400, LINUX_B38400 },
122         { B57600, LINUX_B57600 }, { B115200, LINUX_B115200 },
123         {-1, -1 }
124 };
125
126 struct linux_serial_struct {
127         int     type;
128         int     line;
129         int     port;
130         int     irq;
131         int     flags;
132         int     xmit_fifo_size;
133         int     custom_divisor;
134         int     baud_base;
135         unsigned short close_delay;
136         char    reserved_char[2];
137         int     hub6;
138         unsigned short closing_wait;
139         unsigned short closing_wait2;
140         int     reserved[4];
141 };
142
143 static int
144 linux_to_bsd_speed(int code, struct speedtab *table)
145 {
146         for ( ; table->sp_code != -1; table++)
147                 if (table->sp_code == code)
148                         return (table->sp_speed);
149         return -1;
150 }
151
152 static int
153 bsd_to_linux_speed(int speed, struct speedtab *table)
154 {
155         for ( ; table->sp_speed != -1; table++)
156                 if (table->sp_speed == speed)
157                         return (table->sp_code);
158         return -1;
159 }
160
161 static void
162 bsd_to_linux_termios(struct termios *bios, struct linux_termios *lios)
163 {
164         int i;
165
166 #ifdef DEBUG
167         if (ldebug(ioctl)) {
168                 kprintf("LINUX: BSD termios structure (input):\n");
169                 kprintf("i=%08x o=%08x c=%08x l=%08x ispeed=%d ospeed=%d\n",
170                     bios->c_iflag, bios->c_oflag, bios->c_cflag, bios->c_lflag,
171                     bios->c_ispeed, bios->c_ospeed);
172                 kprintf("c_cc ");
173                 for (i=0; i<NCCS; i++)
174                         kprintf("%02x ", bios->c_cc[i]);
175                 kprintf("\n");
176         }
177 #endif
178
179         lios->c_iflag = 0;
180         if (bios->c_iflag & IGNBRK)
181                 lios->c_iflag |= LINUX_IGNBRK;
182         if (bios->c_iflag & BRKINT)
183                 lios->c_iflag |= LINUX_BRKINT;
184         if (bios->c_iflag & IGNPAR)
185                 lios->c_iflag |= LINUX_IGNPAR;
186         if (bios->c_iflag & PARMRK)
187                 lios->c_iflag |= LINUX_PARMRK;
188         if (bios->c_iflag & INPCK)
189                 lios->c_iflag |= LINUX_INPCK;
190         if (bios->c_iflag & ISTRIP)
191                 lios->c_iflag |= LINUX_ISTRIP;
192         if (bios->c_iflag & INLCR)
193                 lios->c_iflag |= LINUX_INLCR;
194         if (bios->c_iflag & IGNCR)
195                 lios->c_iflag |= LINUX_IGNCR;
196         if (bios->c_iflag & ICRNL)
197                 lios->c_iflag |= LINUX_ICRNL;
198         if (bios->c_iflag & IXON)
199                 lios->c_iflag |= LINUX_IXON;
200         if (bios->c_iflag & IXANY)
201                 lios->c_iflag |= LINUX_IXANY;
202         if (bios->c_iflag & IXOFF)
203                 lios->c_iflag |= LINUX_IXOFF;
204         if (bios->c_iflag & IMAXBEL)
205                 lios->c_iflag |= LINUX_IMAXBEL;
206
207         lios->c_oflag = 0;
208         if (bios->c_oflag & OPOST)
209                 lios->c_oflag |= LINUX_OPOST;
210         if (bios->c_oflag & ONLCR)
211                 lios->c_oflag |= LINUX_ONLCR;
212         if (bios->c_oflag & OXTABS)
213                 lios->c_oflag |= LINUX_XTABS;
214
215         lios->c_cflag = bsd_to_linux_speed(bios->c_ispeed, sptab);
216         lios->c_cflag |= (bios->c_cflag & CSIZE) >> 4;
217         if (bios->c_cflag & CSTOPB)
218                 lios->c_cflag |= LINUX_CSTOPB;
219         if (bios->c_cflag & CREAD)
220                 lios->c_cflag |= LINUX_CREAD;
221         if (bios->c_cflag & PARENB)
222                 lios->c_cflag |= LINUX_PARENB;
223         if (bios->c_cflag & PARODD)
224                 lios->c_cflag |= LINUX_PARODD;
225         if (bios->c_cflag & HUPCL)
226                 lios->c_cflag |= LINUX_HUPCL;
227         if (bios->c_cflag & CLOCAL)
228                 lios->c_cflag |= LINUX_CLOCAL;
229         if (bios->c_cflag & CRTSCTS)
230                 lios->c_cflag |= LINUX_CRTSCTS;
231
232         lios->c_lflag = 0;
233         if (bios->c_lflag & ISIG)
234                 lios->c_lflag |= LINUX_ISIG;
235         if (bios->c_lflag & ICANON)
236                 lios->c_lflag |= LINUX_ICANON;
237         if (bios->c_lflag & ECHO)
238                 lios->c_lflag |= LINUX_ECHO;
239         if (bios->c_lflag & ECHOE)
240                 lios->c_lflag |= LINUX_ECHOE;
241         if (bios->c_lflag & ECHOK)
242                 lios->c_lflag |= LINUX_ECHOK;
243         if (bios->c_lflag & ECHONL)
244                 lios->c_lflag |= LINUX_ECHONL;
245         if (bios->c_lflag & NOFLSH)
246                 lios->c_lflag |= LINUX_NOFLSH;
247         if (bios->c_lflag & TOSTOP)
248                 lios->c_lflag |= LINUX_TOSTOP;
249         if (bios->c_lflag & ECHOCTL)
250                 lios->c_lflag |= LINUX_ECHOCTL;
251         if (bios->c_lflag & ECHOPRT)
252                 lios->c_lflag |= LINUX_ECHOPRT;
253         if (bios->c_lflag & ECHOKE)
254                 lios->c_lflag |= LINUX_ECHOKE;
255         if (bios->c_lflag & FLUSHO)
256                 lios->c_lflag |= LINUX_FLUSHO;
257         if (bios->c_lflag & PENDIN)
258                 lios->c_lflag |= LINUX_PENDIN;
259         if (bios->c_lflag & IEXTEN)
260                 lios->c_lflag |= LINUX_IEXTEN;
261
262         for (i=0; i<LINUX_NCCS; i++)
263                 lios->c_cc[i] = LINUX_POSIX_VDISABLE;
264         lios->c_cc[LINUX_VINTR] = bios->c_cc[VINTR];
265         lios->c_cc[LINUX_VQUIT] = bios->c_cc[VQUIT];
266         lios->c_cc[LINUX_VERASE] = bios->c_cc[VERASE];
267         lios->c_cc[LINUX_VKILL] = bios->c_cc[VKILL];
268         lios->c_cc[LINUX_VEOF] = bios->c_cc[VEOF];
269         lios->c_cc[LINUX_VEOL] = bios->c_cc[VEOL];
270         lios->c_cc[LINUX_VMIN] = bios->c_cc[VMIN];
271         lios->c_cc[LINUX_VTIME] = bios->c_cc[VTIME];
272         lios->c_cc[LINUX_VEOL2] = bios->c_cc[VEOL2];
273         lios->c_cc[LINUX_VSUSP] = bios->c_cc[VSUSP];
274         lios->c_cc[LINUX_VSTART] = bios->c_cc[VSTART];
275         lios->c_cc[LINUX_VSTOP] = bios->c_cc[VSTOP];
276         lios->c_cc[LINUX_VREPRINT] = bios->c_cc[VREPRINT];
277         lios->c_cc[LINUX_VDISCARD] = bios->c_cc[VDISCARD];
278         lios->c_cc[LINUX_VWERASE] = bios->c_cc[VWERASE];
279         lios->c_cc[LINUX_VLNEXT] = bios->c_cc[VLNEXT];
280
281         for (i=0; i<LINUX_NCCS; i++) {
282                  if (i != LINUX_VMIN && i != LINUX_VTIME &&
283                     lios->c_cc[i] == _POSIX_VDISABLE)
284                         lios->c_cc[i] = LINUX_POSIX_VDISABLE;
285         }
286         lios->c_line = 0;
287
288 #ifdef DEBUG
289         if (ldebug(ioctl)) {
290                 kprintf("LINUX: LINUX termios structure (output):\n");
291                 kprintf("i=%08x o=%08x c=%08x l=%08x line=%d\n",
292                     lios->c_iflag, lios->c_oflag, lios->c_cflag,
293                     lios->c_lflag, (int)lios->c_line);
294                 kprintf("c_cc ");
295                 for (i=0; i<LINUX_NCCS; i++) 
296                         kprintf("%02x ", lios->c_cc[i]);
297                 kprintf("\n");
298         }
299 #endif
300 }
301
302 static void
303 linux_to_bsd_termios(struct linux_termios *lios, struct termios *bios)
304 {
305         int i;
306
307 #ifdef DEBUG
308         if (ldebug(ioctl)) {
309                 kprintf("LINUX: LINUX termios structure (input):\n");
310                 kprintf("i=%08x o=%08x c=%08x l=%08x line=%d\n", 
311                     lios->c_iflag, lios->c_oflag, lios->c_cflag,
312                     lios->c_lflag, (int)lios->c_line);
313                 kprintf("c_cc ");
314                 for (i=0; i<LINUX_NCCS; i++)
315                         kprintf("%02x ", lios->c_cc[i]);
316                 kprintf("\n");
317         }
318 #endif
319
320         bios->c_iflag = 0;
321         if (lios->c_iflag & LINUX_IGNBRK)
322                 bios->c_iflag |= IGNBRK;
323         if (lios->c_iflag & LINUX_BRKINT)
324                 bios->c_iflag |= BRKINT;
325         if (lios->c_iflag & LINUX_IGNPAR)
326                 bios->c_iflag |= IGNPAR;
327         if (lios->c_iflag & LINUX_PARMRK)
328                 bios->c_iflag |= PARMRK;
329         if (lios->c_iflag & LINUX_INPCK)
330                 bios->c_iflag |= INPCK;
331         if (lios->c_iflag & LINUX_ISTRIP)
332                 bios->c_iflag |= ISTRIP;
333         if (lios->c_iflag & LINUX_INLCR)
334                 bios->c_iflag |= INLCR;
335         if (lios->c_iflag & LINUX_IGNCR)
336                 bios->c_iflag |= IGNCR;
337         if (lios->c_iflag & LINUX_ICRNL)
338                 bios->c_iflag |= ICRNL;
339         if (lios->c_iflag & LINUX_IXON)
340                 bios->c_iflag |= IXON;
341         if (lios->c_iflag & LINUX_IXANY)
342                 bios->c_iflag |= IXANY;
343         if (lios->c_iflag & LINUX_IXOFF)
344                 bios->c_iflag |= IXOFF;
345         if (lios->c_iflag & LINUX_IMAXBEL)
346                 bios->c_iflag |= IMAXBEL;
347
348         bios->c_oflag = 0;
349         if (lios->c_oflag & LINUX_OPOST)
350                 bios->c_oflag |= OPOST;
351         if (lios->c_oflag & LINUX_ONLCR)
352                 bios->c_oflag |= ONLCR;
353         if (lios->c_oflag & LINUX_XTABS)
354                 bios->c_oflag |= OXTABS;
355
356         bios->c_cflag = (lios->c_cflag & LINUX_CSIZE) << 4;
357         if (lios->c_cflag & LINUX_CSTOPB)
358                 bios->c_cflag |= CSTOPB;
359         if (lios->c_cflag & LINUX_CREAD)
360                 bios->c_cflag |= CREAD;
361         if (lios->c_cflag & LINUX_PARENB)
362                 bios->c_cflag |= PARENB;
363         if (lios->c_cflag & LINUX_PARODD)
364                 bios->c_cflag |= PARODD;
365         if (lios->c_cflag & LINUX_HUPCL)
366                 bios->c_cflag |= HUPCL;
367         if (lios->c_cflag & LINUX_CLOCAL)
368                 bios->c_cflag |= CLOCAL;
369         if (lios->c_cflag & LINUX_CRTSCTS)
370                 bios->c_cflag |= CRTSCTS;
371
372         bios->c_lflag = 0;
373         if (lios->c_lflag & LINUX_ISIG)
374                 bios->c_lflag |= ISIG;
375         if (lios->c_lflag & LINUX_ICANON)
376                 bios->c_lflag |= ICANON;
377         if (lios->c_lflag & LINUX_ECHO)
378                 bios->c_lflag |= ECHO;
379         if (lios->c_lflag & LINUX_ECHOE)
380                 bios->c_lflag |= ECHOE;
381         if (lios->c_lflag & LINUX_ECHOK)
382                 bios->c_lflag |= ECHOK;
383         if (lios->c_lflag & LINUX_ECHONL)
384                 bios->c_lflag |= ECHONL;
385         if (lios->c_lflag & LINUX_NOFLSH)
386                 bios->c_lflag |= NOFLSH;
387         if (lios->c_lflag & LINUX_TOSTOP)
388                 bios->c_lflag |= TOSTOP;
389         if (lios->c_lflag & LINUX_ECHOCTL)
390                 bios->c_lflag |= ECHOCTL;
391         if (lios->c_lflag & LINUX_ECHOPRT)
392                 bios->c_lflag |= ECHOPRT;
393         if (lios->c_lflag & LINUX_ECHOKE)
394                 bios->c_lflag |= ECHOKE;
395         if (lios->c_lflag & LINUX_FLUSHO)
396                 bios->c_lflag |= FLUSHO;
397         if (lios->c_lflag & LINUX_PENDIN)
398                 bios->c_lflag |= PENDIN;
399         if (lios->c_lflag & LINUX_IEXTEN)
400                 bios->c_lflag |= IEXTEN;
401
402         for (i=0; i<NCCS; i++)
403                 bios->c_cc[i] = _POSIX_VDISABLE;
404         bios->c_cc[VINTR] = lios->c_cc[LINUX_VINTR];
405         bios->c_cc[VQUIT] = lios->c_cc[LINUX_VQUIT];
406         bios->c_cc[VERASE] = lios->c_cc[LINUX_VERASE];
407         bios->c_cc[VKILL] = lios->c_cc[LINUX_VKILL];
408         bios->c_cc[VEOF] = lios->c_cc[LINUX_VEOF];
409         bios->c_cc[VEOL] = lios->c_cc[LINUX_VEOL];
410         bios->c_cc[VMIN] = lios->c_cc[LINUX_VMIN];
411         bios->c_cc[VTIME] = lios->c_cc[LINUX_VTIME];
412         bios->c_cc[VEOL2] = lios->c_cc[LINUX_VEOL2];
413         bios->c_cc[VSUSP] = lios->c_cc[LINUX_VSUSP];
414         bios->c_cc[VSTART] = lios->c_cc[LINUX_VSTART];
415         bios->c_cc[VSTOP] = lios->c_cc[LINUX_VSTOP];
416         bios->c_cc[VREPRINT] = lios->c_cc[LINUX_VREPRINT];
417         bios->c_cc[VDISCARD] = lios->c_cc[LINUX_VDISCARD];
418         bios->c_cc[VWERASE] = lios->c_cc[LINUX_VWERASE];
419         bios->c_cc[VLNEXT] = lios->c_cc[LINUX_VLNEXT];
420
421         for (i=0; i<NCCS; i++) {
422                  if (i != VMIN && i != VTIME &&
423                     bios->c_cc[i] == LINUX_POSIX_VDISABLE)
424                         bios->c_cc[i] = _POSIX_VDISABLE;
425         }
426
427         bios->c_ispeed = bios->c_ospeed =
428             linux_to_bsd_speed(lios->c_cflag & LINUX_CBAUD, sptab);
429
430 #ifdef DEBUG
431         if (ldebug(ioctl)) {
432                 kprintf("LINUX: BSD termios structure (output):\n");
433                 kprintf("i=%08x o=%08x c=%08x l=%08x ispeed=%d ospeed=%d\n",
434                     bios->c_iflag, bios->c_oflag, bios->c_cflag, bios->c_lflag,
435                     bios->c_ispeed, bios->c_ospeed);
436                 kprintf("c_cc ");
437                 for (i=0; i<NCCS; i++) 
438                         kprintf("%02x ", bios->c_cc[i]);
439                 kprintf("\n");
440         }
441 #endif
442 }
443
444 static void
445 bsd_to_linux_termio(struct termios *bios, struct linux_termio *lio)
446 {
447         struct linux_termios lios;
448
449         bsd_to_linux_termios(bios, &lios);
450         lio->c_iflag = lios.c_iflag;
451         lio->c_oflag = lios.c_oflag;
452         lio->c_cflag = lios.c_cflag;
453         lio->c_lflag = lios.c_lflag;
454         lio->c_line  = lios.c_line;
455         memcpy(lio->c_cc, lios.c_cc, LINUX_NCC);
456 }
457
458 static void
459 linux_to_bsd_termio(struct linux_termio *lio, struct termios *bios)
460 {
461         struct linux_termios lios;
462         int i;
463
464         lios.c_iflag = lio->c_iflag;
465         lios.c_oflag = lio->c_oflag;
466         lios.c_cflag = lio->c_cflag;
467         lios.c_lflag = lio->c_lflag;
468         for (i=LINUX_NCC; i<LINUX_NCCS; i++)
469                 lios.c_cc[i] = LINUX_POSIX_VDISABLE;
470         memcpy(lios.c_cc, lio->c_cc, LINUX_NCC);
471         linux_to_bsd_termios(&lios, bios);
472 }
473
474 static int
475 linux_ioctl_TCGETS(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
476 {
477         struct termios bios;
478         struct linux_termios lios;
479         int error;
480
481         error = fo_ioctl(fp, TIOCGETA, (caddr_t)&bios, cred);
482         if (error)
483                 return (error);
484         bsd_to_linux_termios(&bios, &lios);
485         bcopy(&lios, data, sizeof(lios));
486         return (0);
487 }
488
489 static int
490 linux_ioctl_TCSETS(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
491 {
492         struct termios bios;
493         struct linux_termios lios;
494
495         bcopy(data, &lios, sizeof(lios));
496         linux_to_bsd_termios(&lios, &bios);
497         return (fo_ioctl(fp, TIOCSETA, (caddr_t)&bios, cred));
498 }
499
500 static int
501 linux_ioctl_TCSETSW(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
502 {
503         struct termios bios;
504         struct linux_termios lios;
505
506         bcopy(data, &lios, sizeof(lios));
507         linux_to_bsd_termios(&lios, &bios);
508         return (fo_ioctl(fp, TIOCSETAW, (caddr_t)&bios, cred));
509 }
510
511 static int
512 linux_ioctl_TCSETSF(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
513 {
514         struct termios bios;
515         struct linux_termios lios;
516
517         bcopy(data, &lios, sizeof(lios));
518         linux_to_bsd_termios(&lios, &bios);
519         return (fo_ioctl(fp, TIOCSETAF, (caddr_t)&bios, cred));
520 }
521
522 static int
523 linux_ioctl_TCGETA(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
524 {
525         struct termios bios;
526         struct linux_termio lio;
527         int error;
528
529         error = fo_ioctl(fp, TIOCGETA, (caddr_t)&bios, cred);
530         if (error)
531                 return (error);
532         bsd_to_linux_termio(&bios, &lio);
533         bcopy(&lio, data, sizeof(lio));
534         return (0);
535 }
536
537 static int
538 linux_ioctl_TCSETA(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
539 {
540         struct termios bios;
541         struct linux_termio lio;
542
543         bcopy(data, &lio, sizeof(lio));
544         linux_to_bsd_termio(&lio, &bios);
545         return (fo_ioctl(fp, TIOCSETA, (caddr_t)&bios, cred));
546 }
547
548 static int
549 linux_ioctl_TCSETAW(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
550 {
551         struct termios bios;
552         struct linux_termio lio;
553
554         bcopy(data, &lio, sizeof(lio));
555         linux_to_bsd_termio(&lio, &bios);
556         return (fo_ioctl(fp, TIOCSETAW, (caddr_t)&bios, cred));
557 }
558
559 static int
560 linux_ioctl_TCSETAF(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
561 {
562         struct termios bios;
563         struct linux_termio lio;
564
565         bcopy(data, &lio, sizeof(lio));
566         linux_to_bsd_termio(&lio, &bios);
567         return (fo_ioctl(fp, TIOCSETAF, (caddr_t)&bios, cred));
568 }
569
570 static int
571 linux_ioctl_TCXONC(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
572 {
573         switch ((u_long)data) {
574         case LINUX_TCOOFF:
575                 cmd = TIOCSTOP;
576                 break;
577         case LINUX_TCOON:
578                 cmd = TIOCSTART;
579                 break;
580         case LINUX_TCIOFF:
581         case LINUX_TCION: {
582                 struct termios bios;
583                 int error, c;
584                 
585                 error = fo_ioctl(fp, TIOCGETA, (caddr_t)&bios, cred);
586                 if (error)
587                         return (error);
588                 c = ((u_long)data == LINUX_TCIOFF) ? VSTOP : VSTART;
589                 c = bios.c_cc[c];
590                 if (c != _POSIX_VDISABLE) {
591                         struct uio auio;
592                         struct iovec aiov;
593
594                         aiov.iov_base = (char *)&c;
595                         aiov.iov_len = sizeof(*bios.c_cc);
596                         auio.uio_iov = &aiov;
597                         auio.uio_iovcnt = 1;
598                         auio.uio_offset = -1;
599                         auio.uio_resid = sizeof(*bios.c_cc);
600                         auio.uio_rw = UIO_WRITE;
601                         auio.uio_segflg = UIO_SYSSPACE;
602                         auio.uio_td = curthread;
603
604                         return (fo_write(fp, &auio, fp->f_cred, 0));
605                 }
606
607                 return (0);
608         }
609         default:
610                 return (EINVAL);
611         }
612         return (fo_ioctl(fp, cmd, 0, cred));
613 }
614
615 static int
616 linux_ioctl_TCFLSH(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
617 {
618         switch ((u_long)data) {
619         case LINUX_TCIFLUSH:
620                 *(u_long *)data = FREAD;
621                 break;
622         case LINUX_TCOFLUSH:
623                 *(u_long *)data = FWRITE;
624                 break;
625         case LINUX_TCIOFLUSH:
626                 *(u_long *)data = FREAD | FWRITE;
627                 break;
628         default:
629                 return (EINVAL);
630         }
631         return (fo_ioctl(fp, TIOCFLUSH, data, cred));
632 }
633
634 static int
635 linux_ioctl_TIOCGSERIAL(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
636 {
637         struct linux_serial_struct lss;
638
639         lss.type = LINUX_PORT_16550A;
640         lss.flags = 0;
641         lss.close_delay = 0;
642         bcopy(&lss, data, sizeof(lss));
643         return (0);
644 }
645
646 static int
647 linux_ioctl_TIOCSSERIAL(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
648 {
649 #if 0
650         struct linux_serial_struct lss;
651
652         bcopy(data, &lss, sizeof(lss));
653         /* XXX - It really helps to have an implementation that
654          * does nothing. NOT!
655          */
656 #endif
657         return (0);
658 }
659
660 static int
661 linux_ioctl_TIOCSETD(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
662 {
663         int line;
664
665         switch ((u_long)data) {
666         case LINUX_N_TTY:
667                 line = TTYDISC;
668                 break;
669         case LINUX_N_SLIP:
670                 line = SLIPDISC;
671                 break;
672         case LINUX_N_PPP:
673                 line = PPPDISC;
674                 break;
675         default:
676                 return (EINVAL);
677         }
678         return (fo_ioctl(fp, TIOCSETD, (caddr_t)&line, cred));
679 }
680
681 static int
682 linux_ioctl_TIOCGETD(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
683 {
684         int linux_line, error;
685         int bsd_line = TTYDISC;
686
687         error = fo_ioctl(fp, TIOCGETD, (caddr_t)&bsd_line, cred);
688         if (error)
689                 return (error);
690         switch (bsd_line) {
691         case TTYDISC:
692                 linux_line = LINUX_N_TTY;
693                 break;
694         case SLIPDISC:
695                 linux_line = LINUX_N_SLIP;
696                 break;
697         case PPPDISC:
698                 linux_line = LINUX_N_PPP;
699                 break;
700         default:
701                 return (EINVAL);
702         }
703         bcopy(&linux_line, data, sizeof(int));
704         return (0);
705 }       
706
707
708 /*
709  * CDROM related ioctls
710  */
711
712 struct linux_cdrom_msf
713 {
714         u_char  cdmsf_min0;
715         u_char  cdmsf_sec0;
716         u_char  cdmsf_frame0;
717         u_char  cdmsf_min1;
718         u_char  cdmsf_sec1;
719         u_char  cdmsf_frame1;
720 };
721
722 struct linux_cdrom_tochdr
723 {
724         u_char  cdth_trk0;
725         u_char  cdth_trk1;
726 };
727
728 union linux_cdrom_addr
729 {
730         struct {
731                 u_char  minute;
732                 u_char  second;
733                 u_char  frame;
734         } msf;
735         int     lba;
736 };
737
738 struct linux_cdrom_tocentry
739 {
740         u_char  cdte_track;     
741         u_char  cdte_adr:4;
742         u_char  cdte_ctrl:4;
743         u_char  cdte_format;    
744         union linux_cdrom_addr cdte_addr;
745         u_char  cdte_datamode;  
746 };
747
748 struct linux_cdrom_subchnl
749 {
750         u_char  cdsc_format;
751         u_char  cdsc_audiostatus;
752         u_char  cdsc_adr:4;
753         u_char  cdsc_ctrl:4;
754         u_char  cdsc_trk;
755         u_char  cdsc_ind;
756         union linux_cdrom_addr cdsc_absaddr;
757         union linux_cdrom_addr cdsc_reladdr;
758 };
759
760 static void
761 bsd_to_linux_msf_lba(u_char af, union msf_lba *bp, union linux_cdrom_addr *lp)
762 {
763         if (af == CD_LBA_FORMAT)
764                 lp->lba = bp->lba;
765         else {
766                 lp->msf.minute = bp->msf.minute;
767                 lp->msf.second = bp->msf.second;
768                 lp->msf.frame = bp->msf.frame;
769         }
770 }
771
772 static void
773 set_linux_cdrom_addr(union linux_cdrom_addr *addr, int format, int lba)
774 {
775         if (format == LINUX_CDROM_MSF) {
776                 addr->msf.frame = lba % 75;
777                 lba /= 75;
778                 lba += 2;
779                 addr->msf.second = lba % 60;
780                 addr->msf.minute = lba / 60;
781         } else
782                 addr->lba = lba;
783 }
784
785 static int
786 linux_ioctl_CDROMREADTOCHDR(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
787 {
788         struct ioc_toc_header th;
789         struct linux_cdrom_tochdr lth;
790         int error;
791
792         error = fo_ioctl(fp, CDIOREADTOCHEADER, (caddr_t)&th, cred);
793         if (error)
794                 return (error);
795         lth.cdth_trk0 = th.starting_track;
796         lth.cdth_trk1 = th.ending_track;
797         bcopy(&lth, data, sizeof(lth));
798         return (0);
799 }
800
801 static int
802 linux_ioctl_CDROMREADTOCENTRY(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
803 {
804         struct linux_cdrom_tocentry *ltep = (struct linux_cdrom_tocentry *)data;
805         struct ioc_read_toc_single_entry irtse;
806         int error;
807
808         irtse.address_format = ltep->cdte_format;
809         irtse.track = ltep->cdte_track;
810         error = fo_ioctl(fp, CDIOREADTOCENTRY, (caddr_t)&irtse, cred);
811         if (error)
812                 return (error);
813
814         ltep->cdte_ctrl = irtse.entry.control;
815         ltep->cdte_adr = irtse.entry.addr_type;
816         bsd_to_linux_msf_lba(irtse.address_format, &irtse.entry.addr,
817                              &ltep->cdte_addr);
818         return (0);
819 }       
820
821 static int
822 linux_ioctl_CDROMSUBCHNL(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
823 {
824         struct linux_cdrom_subchnl *sc = (struct linux_cdrom_subchnl *)data;
825         struct ioc_read_subchannel bsdsc;
826         struct cd_sub_channel_info *bsdinfo;
827         int error;
828         caddr_t sg = stackgap_init();
829
830         bsdinfo = stackgap_alloc(&sg, sizeof(struct cd_sub_channel_info));
831         bsdsc.address_format = CD_LBA_FORMAT;
832         bsdsc.data_format = CD_CURRENT_POSITION;
833         bsdsc.track = 0;
834         bsdsc.data_len = sizeof(struct cd_sub_channel_info);
835         bsdsc.data = bsdinfo;
836         error = fo_ioctl(fp, CDIOCREADSUBCHANNEL, (caddr_t)&bsdsc, cred);
837         if (error)
838                 return (error);
839         sc->cdsc_audiostatus = bsdinfo->header.audio_status;
840         sc->cdsc_adr = bsdinfo->what.position.addr_type;
841         sc->cdsc_ctrl = bsdinfo->what.position.control;
842         sc->cdsc_trk = bsdinfo->what.position.track_number;
843         sc->cdsc_ind = bsdinfo->what.position.index_number;
844         set_linux_cdrom_addr(&sc->cdsc_absaddr, sc->cdsc_format, bsdinfo->what.position.absaddr.lba);
845         set_linux_cdrom_addr(&sc->cdsc_reladdr, sc->cdsc_format, bsdinfo->what.position.reladdr.lba);
846         return (0);
847 }
848
849
850 /*
851  * Sound related ioctls
852  */
853
854 static int
855 linux_ioctl_OSS_GETVERSION(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
856 {
857         int version = linux_get_oss_version(curthread);
858
859         bcopy(&version, data, sizeof(int));
860         return (0);
861 }
862
863
864 /*
865  * Console related ioctls
866  */
867
868 #define ISSIGVALID(sig)         ((sig) > 0 && (sig) < NSIG)
869
870 static int
871 linux_ioctl_KDSKBMODE(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
872 {
873         int kbdmode;
874
875         switch ((u_long)data) {
876         case LINUX_KBD_RAW:
877                 kbdmode = K_RAW;
878                 break;
879         case LINUX_KBD_XLATE:
880                 kbdmode = K_XLATE;
881                 break;
882         case LINUX_KBD_MEDIUMRAW:
883                 kbdmode = K_RAW;
884                 break;
885         default:
886                 return (EINVAL);
887         }
888         return (fo_ioctl(fp, KDSKBMODE, (caddr_t)&kbdmode, cred));
889 }
890
891 static int
892 linux_ioctl_VT_SETMODE(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
893 {
894         struct vt_mode *mode = (struct vt_mode *)data;
895
896         if (!ISSIGVALID(mode->frsig) && ISSIGVALID(mode->acqsig))
897                 mode->frsig = mode->acqsig;
898         return (fo_ioctl(fp, VT_SETMODE, data, cred));
899 }
900
901
902 /*
903  * Socket related ioctls
904  */
905
906 /*
907  * Criteria for interface name translation
908  */
909 #define IFP_IS_ETH(ifp) (ifp->if_type == IFT_ETHER)
910
911 /*
912  * Interface function used by linprocfs (at the time of writing). It's not
913  * used by the Linuxulator itself.
914  */
915 int
916 linux_ifname(struct ifnet *ifp, char *buffer, size_t buflen)
917 {
918         struct ifnet *ifscan;
919         int ethno;
920
921         /* Short-circuit non ethernet interfaces */
922         if (!IFP_IS_ETH(ifp))
923                 return (strlcpy(buffer, ifp->if_xname, buflen));
924
925         /* Determine the (relative) unit number for ethernet interfaces */
926         ethno = 0;
927         TAILQ_FOREACH(ifscan, &ifnet, if_link) {
928                 if (ifscan == ifp)
929                         return (ksnprintf(buffer, buflen, "eth%d", ethno));
930                 if (IFP_IS_ETH(ifscan))
931                         ethno++;
932         }
933
934         return (0);
935 }
936
937 /*
938  * Translate a Linux interface name to a FreeBSD interface name,
939  * and return the associated ifnet structure
940  * bsdname and lxname need to be least IFNAMSIZ bytes long, but
941  * can point to the same buffer.
942  */
943
944 static struct ifnet *
945 ifname_linux_to_bsd(const char *lxname, char *bsdname)
946 {
947         struct ifnet *ifp;
948         int len, unit;
949         char *ep;
950         int is_eth, index;
951
952         for (len = 0; len < LINUX_IFNAMSIZ; ++len)
953                 if (!isalpha(lxname[len]))
954                         break;
955         if (len == 0 || len == LINUX_IFNAMSIZ)
956                 return (NULL);
957         unit = (int)strtoul(lxname + len, &ep, 10);
958         if (ep == NULL || ep == lxname + len || ep >= lxname + LINUX_IFNAMSIZ)
959                 return (NULL);
960         index = 0;
961         is_eth = (len == 3 && !strncmp(lxname, "eth", len)) ? 1 : 0;
962         TAILQ_FOREACH(ifp, &ifnet, if_link) {
963                 /*
964                  * Allow Linux programs to use FreeBSD names. Don't presume
965                  * we never have an interface named "eth", so don't make
966                  * the test optional based on is_eth.
967                  */
968                 if (strncmp(ifp->if_xname, lxname, LINUX_IFNAMSIZ) == 0)
969                         break;
970                 if (is_eth && IFP_IS_ETH(ifp) && unit == index++)
971                         break;
972         }
973         if (ifp != NULL)
974                 strlcpy(bsdname, ifp->if_xname, IFNAMSIZ);
975         return (ifp);
976 }
977
978 static int
979 linux_ioctl_SIOCGIFCONF(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
980 {
981         struct ifconf *ifc = (struct ifconf *)data;
982         struct l_ifreq ifr;
983         struct ifnet *ifp;
984         struct ifaddr *ifa;
985         struct iovec iov;
986         struct uio uio;
987         int error, ethno;
988
989         /* much easier to use uiomove than keep track ourselves */
990         iov.iov_base = ifc->ifc_buf;
991         iov.iov_len = ifc->ifc_len;
992         uio.uio_iov = &iov;
993         uio.uio_iovcnt = 1;
994         uio.uio_offset = 0;
995         uio.uio_resid = ifc->ifc_len;
996         uio.uio_segflg = UIO_USERSPACE;
997         uio.uio_rw = UIO_READ;
998         uio.uio_td = curthread;
999
1000         /* Keep track of eth interfaces */
1001         ethno = 0;
1002
1003         /* Return all AF_INET addresses of all interfaces */
1004         TAILQ_FOREACH(ifp, &ifnet, if_link) {
1005                 if (uio.uio_resid <= 0)
1006                         break;
1007
1008                 bzero(&ifr, sizeof ifr);
1009                 if (IFP_IS_ETH(ifp))
1010                         ksnprintf(ifr.ifr_name, LINUX_IFNAMSIZ, "eth%d",
1011                             ethno++);
1012                 else
1013                         strlcpy(ifr.ifr_name, ifp->if_xname, LINUX_IFNAMSIZ);
1014
1015                 /* Walk the address list */
1016                 TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
1017                         struct sockaddr *sa = ifa->ifa_addr;
1018
1019                         if (uio.uio_resid <= 0)
1020                                 break;
1021
1022                         if (sa->sa_family == AF_INET) {
1023                                 ifr.ifr_addr.sa_family = LINUX_AF_INET;
1024                                 memcpy(ifr.ifr_addr.sa_data, sa->sa_data,
1025                                     sizeof(ifr.ifr_addr.sa_data));
1026
1027                                 error = uiomove((caddr_t)&ifr, sizeof ifr,
1028                                     &uio);
1029                                 if (error != 0)
1030                                         return (error);
1031                         }
1032                 }
1033         }
1034
1035         ifc->ifc_len -= uio.uio_resid;
1036
1037         return (0);
1038 }
1039
1040 static int
1041 linux_ioctl_SIOCGIFFLAGS(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
1042 {
1043         struct l_ifreq *ifr = (struct l_ifreq *)data;
1044         struct ifnet *ifp;
1045         char ifname[IFNAMSIZ];
1046         l_short flags;
1047
1048         if (fp->f_type != DTYPE_SOCKET) {
1049                 /* XXX: I doubt this is correct because
1050                  *      we don't translate the ifname and
1051                  *      use l_ifreq instead of ifreq
1052                  */
1053                 return (fo_ioctl(fp, SIOCGIFFLAGS, data, cred));
1054         }
1055
1056         ifp = ifname_linux_to_bsd(ifr->ifr_name, ifname);
1057         flags = ifp->if_flags;
1058         /* these flags have no Linux equivalent */
1059         flags &= ~(IFF_SMART|IFF_OACTIVE|IFF_SIMPLEX|
1060             IFF_LINK0|IFF_LINK1|IFF_LINK2);
1061         /* Linux' multicast flag is in a different bit */
1062         if (flags & IFF_MULTICAST) {
1063                 flags &= ~IFF_MULTICAST;
1064                 flags |= 0x1000;
1065         }
1066
1067         ifr->ifr_flags = flags;
1068         return (0);
1069 }
1070
1071 #define ARPHRD_ETHER    1
1072 #define ARPHRD_LOOPBACK 772
1073
1074 static int
1075 linux_ioctl_SIOGIFHWADDR(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
1076 {
1077         struct l_ifreq *ifr = (struct l_ifreq *)data;
1078         struct ifnet *ifp;
1079         char ifname[IFNAMSIZ];
1080         struct ifaddr *ifa;
1081         struct sockaddr_dl *sdl;
1082         struct l_sockaddr lsa;
1083
1084         ifp = ifname_linux_to_bsd(ifr->ifr_name, ifname);
1085         if (ifp->if_type == IFT_LOOP) {
1086                 bzero(&ifr->ifr_hwaddr, sizeof lsa);
1087                 ifr->ifr_hwaddr.sa_family = ARPHRD_LOOPBACK;
1088                 return (0);
1089         }
1090         
1091         if (ifp->if_type != IFT_ETHER)
1092                 return (ENOENT);
1093
1094         TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
1095                 sdl = (struct sockaddr_dl*)ifa->ifa_addr;
1096                 if (sdl != NULL && (sdl->sdl_family == AF_LINK) &&
1097                     (sdl->sdl_type == IFT_ETHER)) {
1098                         bzero(&ifr->ifr_hwaddr, sizeof lsa);
1099                         ifr->ifr_hwaddr.sa_family = ARPHRD_ETHER;
1100                         bcopy(LLADDR(sdl), ifr->ifr_hwaddr.sa_data, LINUX_IFHWADDRLEN);
1101                         return (0);
1102                 }
1103         }
1104         
1105         return (ENOENT);
1106 }
1107
1108 static int
1109 linux_ioctl_map_ifname(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
1110 {
1111         struct ifnet *ifp;
1112         int error;
1113         char *oifname = (char *)data;
1114         char lifname[LINUX_IFNAMSIZ];
1115
1116         KASSERT(LINUX_IFNAMSIZ == IFNAMSIZ,
1117             ("%s(): LINUX_IFNAMSIZ != IFNAMSIZ", __func__));
1118         
1119         if (fp->f_type != DTYPE_SOCKET) {
1120                 /*
1121                  *  XXX: I doubt this is correct because
1122                  *       we don't map the ifname
1123                  */
1124                 /* not a socket - probably a tap / vmnet device */
1125                 if (ocmd == LINUX_SIOCGIFADDR || ocmd == LINUX_SIOCSIFADDR) {
1126                         cmd = (ocmd == LINUX_SIOCGIFADDR) ? SIOCGIFADDR : SIOCSIFADDR;
1127                         return (fo_ioctl(fp, cmd, data, cred));
1128                 } else
1129                         return (ENOIOCTL);
1130         }
1131
1132         /* Save the original ifname */
1133         bcopy(oifname, lifname, LINUX_IFNAMSIZ);
1134 #ifdef DEBUG
1135         kprintf("%s(): ioctl %d on %.*s\n", __func__,
1136                 (int)(cmd & 0xffff), LINUX_IFNAMSIZ, lifname);
1137 #endif
1138         /* Replace linux ifname with bsd ifname */
1139         ifp = ifname_linux_to_bsd(lifname, oifname);
1140         if (ifp == NULL) {
1141                 error = EINVAL;
1142                 goto clean_ifname;
1143         }
1144
1145 #ifdef DEBUG
1146         kprintf("%s(): %s translated to %s\n", __func__,
1147                 lifname, oifname);
1148 #endif
1149
1150         error = fo_ioctl(fp, cmd, data, cred);
1151
1152 clean_ifname:
1153         bcopy(lifname, oifname, LINUX_IFNAMSIZ);
1154         return (error);
1155 }
1156
1157
1158 /*
1159  * generic linux -> BSD syscall direction mapper
1160  */
1161 u_long
1162 linux_gen_dirmap(u_long lstart, u_long lend, u_long bstart, u_long bend, u_long cmd, u_long ocmd)
1163 {
1164         static u_int32_t dirbits[4] = { IOC_VOID, IOC_IN, IOC_OUT, IOC_INOUT };
1165
1166         return ((cmd & ~IOC_DIRMASK) | dirbits[ocmd >> 30]);
1167 }
1168
1169
1170 static struct ioctl_map_range linux_ioctl_map_entries[] = {
1171         /* disk ioctl */
1172         MAPPED_IOCTL_IOR(LINUX_BLKGETSIZE, linux_ioctl_BLKGETSIZE32, uint32_t),
1173         /* termio ioctl */
1174         MAPPED_IOCTL_IOR(LINUX_TCGETS, linux_ioctl_TCGETS, struct linux_termios),
1175         MAPPED_IOCTL_IOW(LINUX_TCSETS, linux_ioctl_TCSETS, struct linux_termios),
1176         MAPPED_IOCTL_IOW(LINUX_TCSETSW, linux_ioctl_TCSETSW, struct linux_termios),
1177         MAPPED_IOCTL_IOW(LINUX_TCSETSF, linux_ioctl_TCSETSF, struct linux_termios),
1178         MAPPED_IOCTL_IOR(LINUX_TCGETA, linux_ioctl_TCGETA, struct linux_termio),
1179         MAPPED_IOCTL_IOW(LINUX_TCSETA, linux_ioctl_TCSETA, struct linux_termio),
1180         MAPPED_IOCTL_IOW(LINUX_TCSETAW, linux_ioctl_TCSETAW, struct linux_termio),
1181         MAPPED_IOCTL_IOW(LINUX_TCSETAF, linux_ioctl_TCSETAF, struct linux_termio),
1182         MAPPED_IOCTL_IO(LINUX_TCXONC, linux_ioctl_TCXONC),
1183         MAPPED_IOCTL_IO(LINUX_TCFLSH, linux_ioctl_TCFLSH),
1184         MAPPED_IOCTL_MAP(LINUX_TIOCEXCL, TIOCEXCL),
1185         MAPPED_IOCTL_MAP(LINUX_TIOCNXCL, TIOCNXCL),
1186         MAPPED_IOCTL_MAP(LINUX_TIOCGPGRP, TIOCGPGRP),
1187         MAPPED_IOCTL_MAP(LINUX_TIOCSPGRP, TIOCSPGRP),
1188         MAPPED_IOCTL_MAP(LINUX_TIOCGWINSZ, TIOCGWINSZ),
1189         MAPPED_IOCTL_MAP(LINUX_TIOCSWINSZ, TIOCSWINSZ),
1190         MAPPED_IOCTL_MAP(LINUX_TIOCMGET, TIOCMGET),
1191         MAPPED_IOCTL_MAP(LINUX_TIOCMBIS, TIOCMBIS),
1192         MAPPED_IOCTL_MAP(LINUX_TIOCMBIC, TIOCMBIC),
1193         MAPPED_IOCTL_MAP(LINUX_TIOCMSET, TIOCMSET),
1194         MAPPED_IOCTL_MAP(LINUX_FIONREAD, FIONREAD),
1195         MAPPED_IOCTL_MAP(LINUX_TIOCCONS, TIOCCONS),
1196         MAPPED_IOCTL_IOR(LINUX_TIOCGSERIAL, linux_ioctl_TIOCGSERIAL, struct linux_serial_struct),
1197         MAPPED_IOCTL_IOW(LINUX_TIOCSSERIAL, linux_ioctl_TIOCSSERIAL, struct linux_serial_struct),
1198         MAPPED_IOCTL_MAP(LINUX_FIONBIO, FIONBIO),
1199         MAPPED_IOCTL_MAP(LINUX_TIOCNOTTY, TIOCNOTTY),
1200         MAPPED_IOCTL_IO(LINUX_TIOCSETD, linux_ioctl_TIOCSETD),
1201         MAPPED_IOCTL_IOR(LINUX_TIOCGETD, linux_ioctl_TIOCGETD, int),
1202         MAPPED_IOCTL_MAP(LINUX_FIONCLEX, FIONCLEX),
1203         MAPPED_IOCTL_MAP(LINUX_FIOCLEX, FIOCLEX),
1204         MAPPED_IOCTL_MAP(LINUX_FIOASYNC, FIOASYNC),
1205         /* cdrom ioctl */
1206         MAPPED_IOCTL_MAP(LINUX_CDROMPAUSE, CDIOCPAUSE),
1207         MAPPED_IOCTL_MAP(LINUX_CDROMRESUME, CDIOCRESUME),
1208         MAPPED_IOCTL_MAP(LINUX_CDROMPLAYMSF, CDIOCPLAYMSF),
1209         MAPPED_IOCTL_MAP(LINUX_CDROMPLAYTRKIND, CDIOCPLAYTRACKS),
1210         MAPPED_IOCTL_IOR(LINUX_CDROMREADTOCHDR, linux_ioctl_CDROMREADTOCHDR, struct linux_cdrom_tochdr),
1211         MAPPED_IOCTL_IOWR(LINUX_CDROMREADTOCENTRY, linux_ioctl_CDROMREADTOCENTRY, struct linux_cdrom_tocentry),
1212         MAPPED_IOCTL_MAP(LINUX_CDROMSTOP, CDIOCSTOP),
1213         MAPPED_IOCTL_MAP(LINUX_CDROMSTART, CDIOCSTART),
1214         MAPPED_IOCTL_MAP(LINUX_CDROMEJECT, CDIOCEJECT),
1215         MAPPED_IOCTL_IOWR(LINUX_CDROMSUBCHNL, linux_ioctl_CDROMSUBCHNL, struct linux_cdrom_subchnl),
1216         MAPPED_IOCTL_MAP(LINUX_CDROMRESET, CDIOCRESET),
1217         /* sound ioctl */
1218         MAPPED_IOCTL_MAPRANGE(LINUX_SOUND_MIXER_WRITE_MIN, LINUX_SOUND_MIXER_WRITE_MAX,
1219                               LINUX_SOUND_MIXER_WRITE_MIN, LINUX_SOUND_MIXER_WRITE_MAX,
1220                               NULL, linux_gen_dirmap),
1221         MAPPED_IOCTL_IOR(LINUX_OSS_GETVERSION, linux_ioctl_OSS_GETVERSION, int),
1222         MAPPED_IOCTL_MAP(LINUX_SOUND_MIXER_READ_DEVMASK, SOUND_MIXER_READ_DEVMASK),
1223         MAPPED_IOCTL_MAPRANGE(LINUX_SNDCTL_DSP_MIN, LINUX_SNDCTL_DSP_MAX, LINUX_SNDCTL_DSP_MIN,
1224                               LINUX_SNDCTL_DSP_MAX, NULL, linux_gen_dirmap),
1225         MAPPED_IOCTL_MAPRANGE(LINUX_SNDCTL_SEQ_MIN, LINUX_SNDCTL_SEQ_MAX, LINUX_SNDCTL_SEQ_MIN,
1226                               LINUX_SNDCTL_SEQ_MAX, NULL, linux_gen_dirmap),
1227         /* console ioctl */
1228         MAPPED_IOCTL_MAP(LINUX_KIOCSOUND, KIOCSOUND),
1229         MAPPED_IOCTL_MAP(LINUX_KDMKTONE, KDMKTONE),
1230         MAPPED_IOCTL_MAP(LINUX_KDGETLED, KDGETLED),
1231         MAPPED_IOCTL_MAP(LINUX_KDSETLED, KDSETLED),
1232         MAPPED_IOCTL_MAP(LINUX_KDSETMODE, KDSETMODE),
1233         MAPPED_IOCTL_MAP(LINUX_KDGETMODE, KDGETMODE),
1234         MAPPED_IOCTL_MAP(LINUX_KDGKBMODE, KDGKBMODE),
1235         MAPPED_IOCTL_IOW(LINUX_KDSKBMODE, linux_ioctl_KDSKBMODE, int),
1236         MAPPED_IOCTL_MAP(LINUX_VT_OPENQRY, VT_OPENQRY),
1237         MAPPED_IOCTL_MAP(LINUX_VT_GETMODE, VT_GETMODE),
1238         MAPPED_IOCTL_IOW(LINUX_VT_SETMODE, linux_ioctl_VT_SETMODE, struct vt_mode),
1239         MAPPED_IOCTL_MAP(LINUX_VT_GETSTATE, VT_GETACTIVE),
1240         MAPPED_IOCTL_MAP(LINUX_VT_RELDISP, VT_RELDISP),
1241         MAPPED_IOCTL_MAP(LINUX_VT_ACTIVATE, VT_ACTIVATE),
1242         MAPPED_IOCTL_MAP(LINUX_VT_WAITACTIVE, VT_WAITACTIVE),
1243         /* socket ioctl */
1244         MAPPED_IOCTL_MAP(LINUX_FIOSETOWN, FIOSETOWN),
1245         MAPPED_IOCTL_MAP(LINUX_SIOCSPGRP, SIOCSPGRP),
1246         MAPPED_IOCTL_MAP(LINUX_FIOGETOWN, FIOGETOWN),
1247         MAPPED_IOCTL_MAP(LINUX_SIOCGPGRP, SIOCGPGRP),
1248         MAPPED_IOCTL_MAP(LINUX_SIOCATMARK, SIOCATMARK),
1249         MAPPED_IOCTL_IOWR(LINUX_SIOCGIFCONF, linux_ioctl_SIOCGIFCONF, struct ifconf),
1250         MAPPED_IOCTL_IOWR(LINUX_SIOCGIFFLAGS, linux_ioctl_SIOCGIFFLAGS, struct l_ifreq),
1251         MAPPED_IOCTL_MAPF(LINUX_SIOCGIFADDR, OSIOCGIFADDR, linux_ioctl_map_ifname),
1252         MAPPED_IOCTL_MAPF(LINUX_SIOCSIFADDR, SIOCSIFADDR, linux_ioctl_map_ifname),
1253         MAPPED_IOCTL_MAPF(LINUX_SIOCGIFDSTADDR, OSIOCGIFDSTADDR, linux_ioctl_map_ifname),
1254         MAPPED_IOCTL_MAPF(LINUX_SIOCGIFBRDADDR, OSIOCGIFBRDADDR, linux_ioctl_map_ifname),
1255         MAPPED_IOCTL_MAPF(LINUX_SIOCGIFNETMASK, OSIOCGIFNETMASK, linux_ioctl_map_ifname),
1256         /*MAPPED_IOCTL_IOx(LINUX_SIOCSIFNETMASK, x, x),*/
1257         MAPPED_IOCTL_MAPF(LINUX_SIOCGIFMTU, SIOCGIFMTU, linux_ioctl_map_ifname),
1258         MAPPED_IOCTL_MAPF(LINUX_SIOCSIFMTU, SIOCSIFMTU, linux_ioctl_map_ifname),
1259         MAPPED_IOCTL_IOWR(LINUX_SIOCGIFHWADDR, linux_ioctl_SIOGIFHWADDR, struct l_ifreq),
1260         MAPPED_IOCTL_MAP(LINUX_SIOCADDMULTI, SIOCADDMULTI),
1261         MAPPED_IOCTL_MAP(LINUX_SIOCDELMULTI, SIOCDELMULTI),
1262         /*
1263          * XXX This is slightly bogus, but these ioctls are currently
1264          * XXX only used by the aironet (if_an) network driver.
1265          */
1266         MAPPED_IOCTL_MAPF(LINUX_SIOCDEVPRIVATE, SIOCGPRIVATE_0, linux_ioctl_map_ifname),
1267         MAPPED_IOCTL_MAPF(LINUX_SIOCDEVPRIVATE+1, SIOCGPRIVATE_1, linux_ioctl_map_ifname),
1268         MAPPED_IOCTL_MAPF(0, 0, NULL)
1269         };
1270
1271 struct ioctl_map linux_ioctl_map = {
1272         0xffff,         /* mask */
1273         "linux",        /* subsys */
1274         LIST_HEAD_INITIALIZER(mapping)
1275         };
1276
1277 static struct ioctl_map_handler linux_ioctl_base_handler = {
1278         &linux_ioctl_map,
1279         "base",
1280         linux_ioctl_map_entries
1281         };
1282
1283 /*
1284  * main ioctl syscall function
1285  */
1286
1287 int
1288 sys_linux_ioctl(struct linux_ioctl_args *args)
1289 {
1290 #ifdef DEBUG
1291         if (ldebug(ioctl))
1292                 kprintf(ARGS(ioctl, "%d, %04x, *"), args->fd, args->cmd);
1293 #endif
1294
1295         return (mapped_ioctl(args->fd, args->cmd, (caddr_t)args->arg, &linux_ioctl_map));
1296 }
1297
1298 SYSINIT  (linux_ioctl_register, SI_BOOT2_KLD, SI_ORDER_MIDDLE,
1299           mapped_ioctl_register_handler, &linux_ioctl_base_handler);
1300 SYSUNINIT(linux_ioctl_register, SI_BOOT2_KLD, SI_ORDER_MIDDLE,
1301           mapped_ioctl_unregister_handler, &linux_ioctl_base_handler);