Parallelize ifnet.if_addrhead accessing by duplicating the list itself
[dragonfly.git] / sys / emulation / linux / linux_ioctl.c
blob7846e289c9a8be86ffa45f80d71934e4ac74e034
1 /*
2 * Copyright (c) 1994-1995 Søren Schmidt
3 * Copyright (c) 2004 Simon 'corecode' Schubert
4 * All rights reserved.
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
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.
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 $
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>
61 #include <arch_linux/linux.h>
62 #include <arch_linux/linux_proto.h>
64 #include "linux_ioctl.h"
65 #include "linux_mib.h"
66 #include "linux_util.h"
69 static int
70 linux_ioctl_BLKGETSIZE32(struct file *fp, u_long cmd, u_long ocmd,
71 caddr_t data, struct ucred *cred)
73 struct partinfo dpart;
74 u_int32_t value;
75 int error;
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);
87 * termio related ioctls
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];
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];
108 struct linux_winsize {
109 unsigned short ws_row, ws_col;
110 unsigned short ws_xpixel, ws_ypixel;
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 }
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];
143 static int
144 linux_to_bsd_speed(int code, struct speedtab *table)
146 for ( ; table->sp_code != -1; table++)
147 if (table->sp_code == code)
148 return (table->sp_speed);
149 return -1;
152 static int
153 bsd_to_linux_speed(int speed, struct speedtab *table)
155 for ( ; table->sp_speed != -1; table++)
156 if (table->sp_speed == speed)
157 return (table->sp_code);
158 return -1;
161 static void
162 bsd_to_linux_termios(struct termios *bios, struct linux_termios *lios)
164 int i;
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");
177 #endif
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;
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;
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;
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;
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];
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;
286 lios->c_line = 0;
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");
299 #endif
302 static void
303 linux_to_bsd_termios(struct linux_termios *lios, struct termios *bios)
305 int i;
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");
318 #endif
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;
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;
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;
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;
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];
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;
427 bios->c_ispeed = bios->c_ospeed =
428 linux_to_bsd_speed(lios->c_cflag & LINUX_CBAUD, sptab);
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");
441 #endif
444 static void
445 bsd_to_linux_termio(struct termios *bios, struct linux_termio *lio)
447 struct linux_termios lios;
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);
458 static void
459 linux_to_bsd_termio(struct linux_termio *lio, struct termios *bios)
461 struct linux_termios lios;
462 int i;
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);
474 static int
475 linux_ioctl_TCGETS(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
477 struct termios bios;
478 struct linux_termios lios;
479 int error;
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);
489 static int
490 linux_ioctl_TCSETS(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
492 struct termios bios;
493 struct linux_termios lios;
495 bcopy(data, &lios, sizeof(lios));
496 linux_to_bsd_termios(&lios, &bios);
497 return (fo_ioctl(fp, TIOCSETA, (caddr_t)&bios, cred));
500 static int
501 linux_ioctl_TCSETSW(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
503 struct termios bios;
504 struct linux_termios lios;
506 bcopy(data, &lios, sizeof(lios));
507 linux_to_bsd_termios(&lios, &bios);
508 return (fo_ioctl(fp, TIOCSETAW, (caddr_t)&bios, cred));
511 static int
512 linux_ioctl_TCSETSF(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
514 struct termios bios;
515 struct linux_termios lios;
517 bcopy(data, &lios, sizeof(lios));
518 linux_to_bsd_termios(&lios, &bios);
519 return (fo_ioctl(fp, TIOCSETAF, (caddr_t)&bios, cred));
522 static int
523 linux_ioctl_TCGETA(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
525 struct termios bios;
526 struct linux_termio lio;
527 int error;
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);
537 static int
538 linux_ioctl_TCSETA(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
540 struct termios bios;
541 struct linux_termio lio;
543 bcopy(data, &lio, sizeof(lio));
544 linux_to_bsd_termio(&lio, &bios);
545 return (fo_ioctl(fp, TIOCSETA, (caddr_t)&bios, cred));
548 static int
549 linux_ioctl_TCSETAW(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
551 struct termios bios;
552 struct linux_termio lio;
554 bcopy(data, &lio, sizeof(lio));
555 linux_to_bsd_termio(&lio, &bios);
556 return (fo_ioctl(fp, TIOCSETAW, (caddr_t)&bios, cred));
559 static int
560 linux_ioctl_TCSETAF(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
562 struct termios bios;
563 struct linux_termio lio;
565 bcopy(data, &lio, sizeof(lio));
566 linux_to_bsd_termio(&lio, &bios);
567 return (fo_ioctl(fp, TIOCSETAF, (caddr_t)&bios, cred));
570 static int
571 linux_ioctl_TCXONC(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
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;
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;
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;
604 return (fo_write(fp, &auio, fp->f_cred, 0));
607 return (0);
609 default:
610 return (EINVAL);
612 return (fo_ioctl(fp, cmd, 0, cred));
615 static int
616 linux_ioctl_TCFLSH(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
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);
631 return (fo_ioctl(fp, TIOCFLUSH, data, cred));
634 static int
635 linux_ioctl_TIOCGSERIAL(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
637 struct linux_serial_struct lss;
639 lss.type = LINUX_PORT_16550A;
640 lss.flags = 0;
641 lss.close_delay = 0;
642 bcopy(&lss, data, sizeof(lss));
643 return (0);
646 static int
647 linux_ioctl_TIOCSSERIAL(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
649 #if 0
650 struct linux_serial_struct lss;
652 bcopy(data, &lss, sizeof(lss));
653 /* XXX - It really helps to have an implementation that
654 * does nothing. NOT!
656 #endif
657 return (0);
660 static int
661 linux_ioctl_TIOCSETD(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
663 int line;
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);
678 return (fo_ioctl(fp, TIOCSETD, (caddr_t)&line, cred));
681 static int
682 linux_ioctl_TIOCGETD(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
684 int linux_line, error;
685 int bsd_line = TTYDISC;
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);
703 bcopy(&linux_line, data, sizeof(int));
704 return (0);
709 * CDROM related ioctls
712 struct linux_cdrom_msf
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;
722 struct linux_cdrom_tochdr
724 u_char cdth_trk0;
725 u_char cdth_trk1;
728 union linux_cdrom_addr
730 struct {
731 u_char minute;
732 u_char second;
733 u_char frame;
734 } msf;
735 int lba;
738 struct linux_cdrom_tocentry
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;
748 struct linux_cdrom_subchnl
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;
760 static void
761 bsd_to_linux_msf_lba(u_char af, union msf_lba *bp, union linux_cdrom_addr *lp)
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;
772 static void
773 set_linux_cdrom_addr(union linux_cdrom_addr *addr, int format, int lba)
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;
785 static int
786 linux_ioctl_CDROMREADTOCHDR(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
788 struct ioc_toc_header th;
789 struct linux_cdrom_tochdr lth;
790 int error;
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);
801 static int
802 linux_ioctl_CDROMREADTOCENTRY(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
804 struct linux_cdrom_tocentry *ltep = (struct linux_cdrom_tocentry *)data;
805 struct ioc_read_toc_single_entry irtse;
806 int error;
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);
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);
821 static int
822 linux_ioctl_CDROMSUBCHNL(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
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();
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);
851 * Sound related ioctls
854 static int
855 linux_ioctl_OSS_GETVERSION(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
857 int version = linux_get_oss_version(curthread);
859 bcopy(&version, data, sizeof(int));
860 return (0);
865 * Console related ioctls
868 #define ISSIGVALID(sig) ((sig) > 0 && (sig) < NSIG)
870 static int
871 linux_ioctl_KDSKBMODE(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
873 int kbdmode;
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);
888 return (fo_ioctl(fp, KDSKBMODE, (caddr_t)&kbdmode, cred));
891 static int
892 linux_ioctl_VT_SETMODE(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
894 struct vt_mode *mode = (struct vt_mode *)data;
896 if (!ISSIGVALID(mode->frsig) && ISSIGVALID(mode->acqsig))
897 mode->frsig = mode->acqsig;
898 return (fo_ioctl(fp, VT_SETMODE, data, cred));
903 * Socket related ioctls
907 * Criteria for interface name translation
909 #define IFP_IS_ETH(ifp) (ifp->if_type == IFT_ETHER)
912 * Interface function used by linprocfs (at the time of writing). It's not
913 * used by the Linuxulator itself.
916 linux_ifname(struct ifnet *ifp, char *buffer, size_t buflen)
918 struct ifnet *ifscan;
919 int ethno;
921 /* Short-circuit non ethernet interfaces */
922 if (!IFP_IS_ETH(ifp))
923 return (strlcpy(buffer, ifp->if_xname, buflen));
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++;
934 return (0);
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.
944 static struct ifnet *
945 ifname_linux_to_bsd(const char *lxname, char *bsdname)
947 struct ifnet *ifp;
948 int len, unit;
949 char *ep;
950 int is_eth, index;
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) {
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.
968 if (strncmp(ifp->if_xname, lxname, LINUX_IFNAMSIZ) == 0)
969 break;
970 if (is_eth && IFP_IS_ETH(ifp) && unit == index++)
971 break;
973 if (ifp != NULL)
974 strlcpy(bsdname, ifp->if_xname, IFNAMSIZ);
975 return (ifp);
978 static int
979 linux_ioctl_SIOCGIFCONF(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
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;
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;
999 /* Keep track of eth interfaces */
1000 ethno = 0;
1002 /* Return all AF_INET addresses of all interfaces */
1003 TAILQ_FOREACH(ifp, &ifnet, if_link) {
1004 struct ifaddr_container *ifac;
1006 if (uio.uio_resid <= 0)
1007 break;
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);
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;
1021 if (uio.uio_resid <= 0)
1022 break;
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));
1029 error = uiomove((caddr_t)&ifr, sizeof ifr,
1030 &uio);
1031 if (error != 0)
1032 return (error);
1037 ifc->ifc_len -= uio.uio_resid;
1039 return (0);
1042 static int
1043 linux_ioctl_SIOCGIFFLAGS(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
1045 struct l_ifreq *ifr = (struct l_ifreq *)data;
1046 struct ifnet *ifp;
1047 char ifname[IFNAMSIZ];
1048 l_short flags;
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
1055 return (fo_ioctl(fp, SIOCGIFFLAGS, data, cred));
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;
1069 ifr->ifr_flags = flags;
1070 return (0);
1073 #define ARPHRD_ETHER 1
1074 #define ARPHRD_LOOPBACK 772
1076 static int
1077 linux_ioctl_SIOGIFHWADDR(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
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;
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);
1093 if (ifp->if_type != IFT_ETHER)
1094 return (ENOENT);
1096 TAILQ_FOREACH(ifac, &ifp->if_addrheads[mycpuid], ifa_link) {
1097 struct ifaddr *ifa = ifac->ifa;
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);
1109 return (ENOENT);
1112 static int
1113 linux_ioctl_map_ifname(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
1115 struct ifnet *ifp;
1116 int error;
1117 char *oifname = (char *)data;
1118 char lifname[LINUX_IFNAMSIZ];
1120 KASSERT(LINUX_IFNAMSIZ == IFNAMSIZ,
1121 ("%s(): LINUX_IFNAMSIZ != IFNAMSIZ", __func__));
1123 if (fp->f_type != DTYPE_SOCKET) {
1125 * XXX: I doubt this is correct because
1126 * we don't map the ifname
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);
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;
1149 #ifdef DEBUG
1150 kprintf("%s(): %s translated to %s\n", __func__,
1151 lifname, oifname);
1152 #endif
1154 error = fo_ioctl(fp, cmd, data, cred);
1156 clean_ifname:
1157 bcopy(lifname, oifname, LINUX_IFNAMSIZ);
1158 return (error);
1163 * generic linux -> BSD syscall direction mapper
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)
1168 static u_int32_t dirbits[4] = { IOC_VOID, IOC_IN, IOC_OUT, IOC_INOUT };
1170 return ((cmd & ~IOC_DIRMASK) | dirbits[ocmd >> 30]);
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),
1267 * XXX This is slightly bogus, but these ioctls are currently
1268 * XXX only used by the aironet (if_an) network driver.
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)
1275 struct ioctl_map linux_ioctl_map = {
1276 0xffff, /* mask */
1277 "linux", /* subsys */
1278 LIST_HEAD_INITIALIZER(mapping)
1281 static struct ioctl_map_handler linux_ioctl_base_handler = {
1282 &linux_ioctl_map,
1283 "base",
1284 linux_ioctl_map_entries
1288 * main ioctl syscall function
1292 sys_linux_ioctl(struct linux_ioctl_args *args)
1294 #ifdef DEBUG
1295 if (ldebug(ioctl))
1296 kprintf(ARGS(ioctl, "%d, %04x, *"), args->fd, args->cmd);
1297 #endif
1299 return (mapped_ioctl(args->fd, args->cmd, (caddr_t)args->arg, &linux_ioctl_map));
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);