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