Parallelize ifnet.if_addrhead accessing by duplicating the list itself
[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.25 2008/03/07 11:34:19 sephe 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 iovec iov;
985         struct uio uio;
986         int error, ethno;
987
988         /* much easier to use uiomove than keep track ourselves */
989         iov.iov_base = ifc->ifc_buf;
990         iov.iov_len = ifc->ifc_len;
991         uio.uio_iov = &iov;
992         uio.uio_iovcnt = 1;
993         uio.uio_offset = 0;
994         uio.uio_resid = ifc->ifc_len;
995         uio.uio_segflg = UIO_USERSPACE;
996         uio.uio_rw = UIO_READ;
997         uio.uio_td = curthread;
998
999         /* Keep track of eth interfaces */
1000         ethno = 0;
1001
1002         /* Return all AF_INET addresses of all interfaces */
1003         TAILQ_FOREACH(ifp, &ifnet, if_link) {
1004                 struct ifaddr_container *ifac;
1005
1006                 if (uio.uio_resid <= 0)
1007                         break;
1008
1009                 bzero(&ifr, sizeof ifr);
1010                 if (IFP_IS_ETH(ifp))
1011                         ksnprintf(ifr.ifr_name, LINUX_IFNAMSIZ, "eth%d",
1012                             ethno++);
1013                 else
1014                         strlcpy(ifr.ifr_name, ifp->if_xname, LINUX_IFNAMSIZ);
1015
1016                 /* Walk the address list */
1017                 TAILQ_FOREACH(ifac, &ifp->if_addrheads[mycpuid], ifa_link) {
1018                         struct ifaddr *ifa = ifac->ifa;
1019                         struct sockaddr *sa = ifa->ifa_addr;
1020
1021                         if (uio.uio_resid <= 0)
1022                                 break;
1023
1024                         if (sa->sa_family == AF_INET) {
1025                                 ifr.ifr_addr.sa_family = LINUX_AF_INET;
1026                                 memcpy(ifr.ifr_addr.sa_data, sa->sa_data,
1027                                     sizeof(ifr.ifr_addr.sa_data));
1028
1029                                 error = uiomove((caddr_t)&ifr, sizeof ifr,
1030                                     &uio);
1031                                 if (error != 0)
1032                                         return (error);
1033                         }
1034                 }
1035         }
1036
1037         ifc->ifc_len -= uio.uio_resid;
1038
1039         return (0);
1040 }
1041
1042 static int
1043 linux_ioctl_SIOCGIFFLAGS(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
1044 {
1045         struct l_ifreq *ifr = (struct l_ifreq *)data;
1046         struct ifnet *ifp;
1047         char ifname[IFNAMSIZ];
1048         l_short flags;
1049
1050         if (fp->f_type != DTYPE_SOCKET) {
1051                 /* XXX: I doubt this is correct because
1052                  *      we don't translate the ifname and
1053                  *      use l_ifreq instead of ifreq
1054                  */
1055                 return (fo_ioctl(fp, SIOCGIFFLAGS, data, cred));
1056         }
1057
1058         ifp = ifname_linux_to_bsd(ifr->ifr_name, ifname);
1059         flags = ifp->if_flags;
1060         /* these flags have no Linux equivalent */
1061         flags &= ~(IFF_SMART|IFF_OACTIVE|IFF_SIMPLEX|
1062             IFF_LINK0|IFF_LINK1|IFF_LINK2);
1063         /* Linux' multicast flag is in a different bit */
1064         if (flags & IFF_MULTICAST) {
1065                 flags &= ~IFF_MULTICAST;
1066                 flags |= 0x1000;
1067         }
1068
1069         ifr->ifr_flags = flags;
1070         return (0);
1071 }
1072
1073 #define ARPHRD_ETHER    1
1074 #define ARPHRD_LOOPBACK 772
1075
1076 static int
1077 linux_ioctl_SIOGIFHWADDR(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
1078 {
1079         struct l_ifreq *ifr = (struct l_ifreq *)data;
1080         struct ifnet *ifp;
1081         char ifname[IFNAMSIZ];
1082         struct sockaddr_dl *sdl;
1083         struct l_sockaddr lsa;
1084         struct ifaddr_container *ifac;
1085
1086         ifp = ifname_linux_to_bsd(ifr->ifr_name, ifname);
1087         if (ifp->if_type == IFT_LOOP) {
1088                 bzero(&ifr->ifr_hwaddr, sizeof lsa);
1089                 ifr->ifr_hwaddr.sa_family = ARPHRD_LOOPBACK;
1090                 return (0);
1091         }
1092         
1093         if (ifp->if_type != IFT_ETHER)
1094                 return (ENOENT);
1095
1096         TAILQ_FOREACH(ifac, &ifp->if_addrheads[mycpuid], ifa_link) {
1097                 struct ifaddr *ifa = ifac->ifa;
1098
1099                 sdl = (struct sockaddr_dl*)ifa->ifa_addr;
1100                 if (sdl != NULL && (sdl->sdl_family == AF_LINK) &&
1101                     (sdl->sdl_type == IFT_ETHER)) {
1102                         bzero(&ifr->ifr_hwaddr, sizeof lsa);
1103                         ifr->ifr_hwaddr.sa_family = ARPHRD_ETHER;
1104                         bcopy(LLADDR(sdl), ifr->ifr_hwaddr.sa_data, LINUX_IFHWADDRLEN);
1105                         return (0);
1106                 }
1107         }
1108         
1109         return (ENOENT);
1110 }
1111
1112 static int
1113 linux_ioctl_map_ifname(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
1114 {
1115         struct ifnet *ifp;
1116         int error;
1117         char *oifname = (char *)data;
1118         char lifname[LINUX_IFNAMSIZ];
1119
1120         KASSERT(LINUX_IFNAMSIZ == IFNAMSIZ,
1121             ("%s(): LINUX_IFNAMSIZ != IFNAMSIZ", __func__));
1122         
1123         if (fp->f_type != DTYPE_SOCKET) {
1124                 /*
1125                  *  XXX: I doubt this is correct because
1126                  *       we don't map the ifname
1127                  */
1128                 /* not a socket - probably a tap / vmnet device */
1129                 if (ocmd == LINUX_SIOCGIFADDR || ocmd == LINUX_SIOCSIFADDR) {
1130                         cmd = (ocmd == LINUX_SIOCGIFADDR) ? SIOCGIFADDR : SIOCSIFADDR;
1131                         return (fo_ioctl(fp, cmd, data, cred));
1132                 } else
1133                         return (ENOIOCTL);
1134         }
1135
1136         /* Save the original ifname */
1137         bcopy(oifname, lifname, LINUX_IFNAMSIZ);
1138 #ifdef DEBUG
1139         kprintf("%s(): ioctl %d on %.*s\n", __func__,
1140                 (int)(cmd & 0xffff), LINUX_IFNAMSIZ, lifname);
1141 #endif
1142         /* Replace linux ifname with bsd ifname */
1143         ifp = ifname_linux_to_bsd(lifname, oifname);
1144         if (ifp == NULL) {
1145                 error = EINVAL;
1146                 goto clean_ifname;
1147         }
1148
1149 #ifdef DEBUG
1150         kprintf("%s(): %s translated to %s\n", __func__,
1151                 lifname, oifname);
1152 #endif
1153
1154         error = fo_ioctl(fp, cmd, data, cred);
1155
1156 clean_ifname:
1157         bcopy(lifname, oifname, LINUX_IFNAMSIZ);
1158         return (error);
1159 }
1160
1161
1162 /*
1163  * generic linux -> BSD syscall direction mapper
1164  */
1165 u_long
1166 linux_gen_dirmap(u_long lstart, u_long lend, u_long bstart, u_long bend, u_long cmd, u_long ocmd)
1167 {
1168         static u_int32_t dirbits[4] = { IOC_VOID, IOC_IN, IOC_OUT, IOC_INOUT };
1169
1170         return ((cmd & ~IOC_DIRMASK) | dirbits[ocmd >> 30]);
1171 }
1172
1173
1174 static struct ioctl_map_range linux_ioctl_map_entries[] = {
1175         /* disk ioctl */
1176         MAPPED_IOCTL_IOR(LINUX_BLKGETSIZE, linux_ioctl_BLKGETSIZE32, uint32_t),
1177         /* termio ioctl */
1178         MAPPED_IOCTL_IOR(LINUX_TCGETS, linux_ioctl_TCGETS, struct linux_termios),
1179         MAPPED_IOCTL_IOW(LINUX_TCSETS, linux_ioctl_TCSETS, struct linux_termios),
1180         MAPPED_IOCTL_IOW(LINUX_TCSETSW, linux_ioctl_TCSETSW, struct linux_termios),
1181         MAPPED_IOCTL_IOW(LINUX_TCSETSF, linux_ioctl_TCSETSF, struct linux_termios),
1182         MAPPED_IOCTL_IOR(LINUX_TCGETA, linux_ioctl_TCGETA, struct linux_termio),
1183         MAPPED_IOCTL_IOW(LINUX_TCSETA, linux_ioctl_TCSETA, struct linux_termio),
1184         MAPPED_IOCTL_IOW(LINUX_TCSETAW, linux_ioctl_TCSETAW, struct linux_termio),
1185         MAPPED_IOCTL_IOW(LINUX_TCSETAF, linux_ioctl_TCSETAF, struct linux_termio),
1186         MAPPED_IOCTL_IO(LINUX_TCXONC, linux_ioctl_TCXONC),
1187         MAPPED_IOCTL_IO(LINUX_TCFLSH, linux_ioctl_TCFLSH),
1188         MAPPED_IOCTL_MAP(LINUX_TIOCEXCL, TIOCEXCL),
1189         MAPPED_IOCTL_MAP(LINUX_TIOCNXCL, TIOCNXCL),
1190         MAPPED_IOCTL_MAP(LINUX_TIOCGPGRP, TIOCGPGRP),
1191         MAPPED_IOCTL_MAP(LINUX_TIOCSPGRP, TIOCSPGRP),
1192         MAPPED_IOCTL_MAP(LINUX_TIOCGWINSZ, TIOCGWINSZ),
1193         MAPPED_IOCTL_MAP(LINUX_TIOCSWINSZ, TIOCSWINSZ),
1194         MAPPED_IOCTL_MAP(LINUX_TIOCMGET, TIOCMGET),
1195         MAPPED_IOCTL_MAP(LINUX_TIOCMBIS, TIOCMBIS),
1196         MAPPED_IOCTL_MAP(LINUX_TIOCMBIC, TIOCMBIC),
1197         MAPPED_IOCTL_MAP(LINUX_TIOCMSET, TIOCMSET),
1198         MAPPED_IOCTL_MAP(LINUX_FIONREAD, FIONREAD),
1199         MAPPED_IOCTL_MAP(LINUX_TIOCCONS, TIOCCONS),
1200         MAPPED_IOCTL_IOR(LINUX_TIOCGSERIAL, linux_ioctl_TIOCGSERIAL, struct linux_serial_struct),
1201         MAPPED_IOCTL_IOW(LINUX_TIOCSSERIAL, linux_ioctl_TIOCSSERIAL, struct linux_serial_struct),
1202         MAPPED_IOCTL_MAP(LINUX_FIONBIO, FIONBIO),
1203         MAPPED_IOCTL_MAP(LINUX_TIOCNOTTY, TIOCNOTTY),
1204         MAPPED_IOCTL_IO(LINUX_TIOCSETD, linux_ioctl_TIOCSETD),
1205         MAPPED_IOCTL_IOR(LINUX_TIOCGETD, linux_ioctl_TIOCGETD, int),
1206         MAPPED_IOCTL_MAP(LINUX_FIONCLEX, FIONCLEX),
1207         MAPPED_IOCTL_MAP(LINUX_FIOCLEX, FIOCLEX),
1208         MAPPED_IOCTL_MAP(LINUX_FIOASYNC, FIOASYNC),
1209         /* cdrom ioctl */
1210         MAPPED_IOCTL_MAP(LINUX_CDROMPAUSE, CDIOCPAUSE),
1211         MAPPED_IOCTL_MAP(LINUX_CDROMRESUME, CDIOCRESUME),
1212         MAPPED_IOCTL_MAP(LINUX_CDROMPLAYMSF, CDIOCPLAYMSF),
1213         MAPPED_IOCTL_MAP(LINUX_CDROMPLAYTRKIND, CDIOCPLAYTRACKS),
1214         MAPPED_IOCTL_IOR(LINUX_CDROMREADTOCHDR, linux_ioctl_CDROMREADTOCHDR, struct linux_cdrom_tochdr),
1215         MAPPED_IOCTL_IOWR(LINUX_CDROMREADTOCENTRY, linux_ioctl_CDROMREADTOCENTRY, struct linux_cdrom_tocentry),
1216         MAPPED_IOCTL_MAP(LINUX_CDROMSTOP, CDIOCSTOP),
1217         MAPPED_IOCTL_MAP(LINUX_CDROMSTART, CDIOCSTART),
1218         MAPPED_IOCTL_MAP(LINUX_CDROMEJECT, CDIOCEJECT),
1219         MAPPED_IOCTL_IOWR(LINUX_CDROMSUBCHNL, linux_ioctl_CDROMSUBCHNL, struct linux_cdrom_subchnl),
1220         MAPPED_IOCTL_MAP(LINUX_CDROMRESET, CDIOCRESET),
1221         /* sound ioctl */
1222         MAPPED_IOCTL_MAPRANGE(LINUX_SOUND_MIXER_WRITE_MIN, LINUX_SOUND_MIXER_WRITE_MAX,
1223                               LINUX_SOUND_MIXER_WRITE_MIN, LINUX_SOUND_MIXER_WRITE_MAX,
1224                               NULL, linux_gen_dirmap),
1225         MAPPED_IOCTL_IOR(LINUX_OSS_GETVERSION, linux_ioctl_OSS_GETVERSION, int),
1226         MAPPED_IOCTL_MAP(LINUX_SOUND_MIXER_READ_DEVMASK, SOUND_MIXER_READ_DEVMASK),
1227         MAPPED_IOCTL_MAPRANGE(LINUX_SNDCTL_DSP_MIN, LINUX_SNDCTL_DSP_MAX, LINUX_SNDCTL_DSP_MIN,
1228                               LINUX_SNDCTL_DSP_MAX, NULL, linux_gen_dirmap),
1229         MAPPED_IOCTL_MAPRANGE(LINUX_SNDCTL_SEQ_MIN, LINUX_SNDCTL_SEQ_MAX, LINUX_SNDCTL_SEQ_MIN,
1230                               LINUX_SNDCTL_SEQ_MAX, NULL, linux_gen_dirmap),
1231         /* console ioctl */
1232         MAPPED_IOCTL_MAP(LINUX_KIOCSOUND, KIOCSOUND),
1233         MAPPED_IOCTL_MAP(LINUX_KDMKTONE, KDMKTONE),
1234         MAPPED_IOCTL_MAP(LINUX_KDGETLED, KDGETLED),
1235         MAPPED_IOCTL_MAP(LINUX_KDSETLED, KDSETLED),
1236         MAPPED_IOCTL_MAP(LINUX_KDSETMODE, KDSETMODE),
1237         MAPPED_IOCTL_MAP(LINUX_KDGETMODE, KDGETMODE),
1238         MAPPED_IOCTL_MAP(LINUX_KDGKBMODE, KDGKBMODE),
1239         MAPPED_IOCTL_IOW(LINUX_KDSKBMODE, linux_ioctl_KDSKBMODE, int),
1240         MAPPED_IOCTL_MAP(LINUX_VT_OPENQRY, VT_OPENQRY),
1241         MAPPED_IOCTL_MAP(LINUX_VT_GETMODE, VT_GETMODE),
1242         MAPPED_IOCTL_IOW(LINUX_VT_SETMODE, linux_ioctl_VT_SETMODE, struct vt_mode),
1243         MAPPED_IOCTL_MAP(LINUX_VT_GETSTATE, VT_GETACTIVE),
1244         MAPPED_IOCTL_MAP(LINUX_VT_RELDISP, VT_RELDISP),
1245         MAPPED_IOCTL_MAP(LINUX_VT_ACTIVATE, VT_ACTIVATE),
1246         MAPPED_IOCTL_MAP(LINUX_VT_WAITACTIVE, VT_WAITACTIVE),
1247         /* socket ioctl */
1248         MAPPED_IOCTL_MAP(LINUX_FIOSETOWN, FIOSETOWN),
1249         MAPPED_IOCTL_MAP(LINUX_SIOCSPGRP, SIOCSPGRP),
1250         MAPPED_IOCTL_MAP(LINUX_FIOGETOWN, FIOGETOWN),
1251         MAPPED_IOCTL_MAP(LINUX_SIOCGPGRP, SIOCGPGRP),
1252         MAPPED_IOCTL_MAP(LINUX_SIOCATMARK, SIOCATMARK),
1253         MAPPED_IOCTL_IOWR(LINUX_SIOCGIFCONF, linux_ioctl_SIOCGIFCONF, struct ifconf),
1254         MAPPED_IOCTL_IOWR(LINUX_SIOCGIFFLAGS, linux_ioctl_SIOCGIFFLAGS, struct l_ifreq),
1255         MAPPED_IOCTL_MAPF(LINUX_SIOCGIFADDR, OSIOCGIFADDR, linux_ioctl_map_ifname),
1256         MAPPED_IOCTL_MAPF(LINUX_SIOCSIFADDR, SIOCSIFADDR, linux_ioctl_map_ifname),
1257         MAPPED_IOCTL_MAPF(LINUX_SIOCGIFDSTADDR, OSIOCGIFDSTADDR, linux_ioctl_map_ifname),
1258         MAPPED_IOCTL_MAPF(LINUX_SIOCGIFBRDADDR, OSIOCGIFBRDADDR, linux_ioctl_map_ifname),
1259         MAPPED_IOCTL_MAPF(LINUX_SIOCGIFNETMASK, OSIOCGIFNETMASK, linux_ioctl_map_ifname),
1260         /*MAPPED_IOCTL_IOx(LINUX_SIOCSIFNETMASK, x, x),*/
1261         MAPPED_IOCTL_MAPF(LINUX_SIOCGIFMTU, SIOCGIFMTU, linux_ioctl_map_ifname),
1262         MAPPED_IOCTL_MAPF(LINUX_SIOCSIFMTU, SIOCSIFMTU, linux_ioctl_map_ifname),
1263         MAPPED_IOCTL_IOWR(LINUX_SIOCGIFHWADDR, linux_ioctl_SIOGIFHWADDR, struct l_ifreq),
1264         MAPPED_IOCTL_MAP(LINUX_SIOCADDMULTI, SIOCADDMULTI),
1265         MAPPED_IOCTL_MAP(LINUX_SIOCDELMULTI, SIOCDELMULTI),
1266         /*
1267          * XXX This is slightly bogus, but these ioctls are currently
1268          * XXX only used by the aironet (if_an) network driver.
1269          */
1270         MAPPED_IOCTL_MAPF(LINUX_SIOCDEVPRIVATE, SIOCGPRIVATE_0, linux_ioctl_map_ifname),
1271         MAPPED_IOCTL_MAPF(LINUX_SIOCDEVPRIVATE+1, SIOCGPRIVATE_1, linux_ioctl_map_ifname),
1272         MAPPED_IOCTL_MAPF(0, 0, NULL)
1273         };
1274
1275 struct ioctl_map linux_ioctl_map = {
1276         0xffff,         /* mask */
1277         "linux",        /* subsys */
1278         LIST_HEAD_INITIALIZER(mapping)
1279         };
1280
1281 static struct ioctl_map_handler linux_ioctl_base_handler = {
1282         &linux_ioctl_map,
1283         "base",
1284         linux_ioctl_map_entries
1285         };
1286
1287 /*
1288  * main ioctl syscall function
1289  */
1290
1291 int
1292 sys_linux_ioctl(struct linux_ioctl_args *args)
1293 {
1294 #ifdef DEBUG
1295         if (ldebug(ioctl))
1296                 kprintf(ARGS(ioctl, "%d, %04x, *"), args->fd, args->cmd);
1297 #endif
1298
1299         return (mapped_ioctl(args->fd, args->cmd, (caddr_t)args->arg, &linux_ioctl_map));
1300 }
1301
1302 SYSINIT  (linux_ioctl_register, SI_BOOT2_KLD, SI_ORDER_MIDDLE,
1303           mapped_ioctl_register_handler, &linux_ioctl_base_handler);
1304 SYSUNINIT(linux_ioctl_register, SI_BOOT2_KLD, SI_ORDER_MIDDLE,
1305           mapped_ioctl_unregister_handler, &linux_ioctl_base_handler);