1 /*
2 * Copyright (c) 1994-1995 Søren Schmidt
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer
10 * in this position and unchanged.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software withough specific prior written permission
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * $FreeBSD$
29 */
30
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/sysproto.h>
34 #include <sys/cdio.h>
35 #include <sys/consio.h>
36 #include <sys/ctype.h>
37 #include <sys/disklabel.h>
38 #include <sys/fcntl.h>
39 #include <sys/file.h>
40 #include <sys/filedesc.h>
41 #include <sys/filio.h>
42 #include <sys/kbio.h>
43 #include <sys/linker_set.h>
44 #include <sys/malloc.h>
45 #include <sys/proc.h>
46 #include <sys/socket.h>
47 #include <sys/sockio.h>
48 #include <sys/soundcard.h>
49 #include <sys/tty.h>
50 #include <sys/uio.h>
51 #include <net/if.h>
52 #include <net/if_dl.h>
53 #include <net/if_types.h>
54
55 #include <machine/../linux/linux.h>
56 #include <machine/../linux/linux_proto.h>
57
58 #include <compat/linux/linux_ioctl.h>
59 #include <compat/linux/linux_mib.h>
60 #include <compat/linux/linux_util.h>
61
62 static linux_ioctl_function_t linux_ioctl_cdrom;
63 static linux_ioctl_function_t linux_ioctl_console;
64 static linux_ioctl_function_t linux_ioctl_disk;
65 static linux_ioctl_function_t linux_ioctl_socket;
66 static linux_ioctl_function_t linux_ioctl_sound;
67 static linux_ioctl_function_t linux_ioctl_termio;
68 static linux_ioctl_function_t linux_ioctl_private;
69 static linux_ioctl_function_t linux_ioctl_drm;
70 static linux_ioctl_function_t linux_ioctl_special;
71
72 static struct linux_ioctl_handler cdrom_handler =
73 { linux_ioctl_cdrom, LINUX_IOCTL_CDROM_MIN, LINUX_IOCTL_CDROM_MAX };
74 static struct linux_ioctl_handler console_handler =
75 { linux_ioctl_console, LINUX_IOCTL_CONSOLE_MIN, LINUX_IOCTL_CONSOLE_MAX };
76 static struct linux_ioctl_handler disk_handler =
77 { linux_ioctl_disk, LINUX_IOCTL_DISK_MIN, LINUX_IOCTL_DISK_MAX };
78 static struct linux_ioctl_handler socket_handler =
79 { linux_ioctl_socket, LINUX_IOCTL_SOCKET_MIN, LINUX_IOCTL_SOCKET_MAX };
80 static struct linux_ioctl_handler sound_handler =
81 { linux_ioctl_sound, LINUX_IOCTL_SOUND_MIN, LINUX_IOCTL_SOUND_MAX };
82 static struct linux_ioctl_handler termio_handler =
83 { linux_ioctl_termio, LINUX_IOCTL_TERMIO_MIN, LINUX_IOCTL_TERMIO_MAX };
84 static struct linux_ioctl_handler private_handler =
85 { linux_ioctl_private, LINUX_IOCTL_PRIVATE_MIN, LINUX_IOCTL_PRIVATE_MAX };
86 static struct linux_ioctl_handler drm_handler =
87 { linux_ioctl_drm, LINUX_IOCTL_DRM_MIN, LINUX_IOCTL_DRM_MAX };
88
89 DATA_SET(linux_ioctl_handler_set, cdrom_handler);
90 DATA_SET(linux_ioctl_handler_set, console_handler);
91 DATA_SET(linux_ioctl_handler_set, disk_handler);
92 DATA_SET(linux_ioctl_handler_set, socket_handler);
93 DATA_SET(linux_ioctl_handler_set, sound_handler);
94 DATA_SET(linux_ioctl_handler_set, termio_handler);
95 DATA_SET(linux_ioctl_handler_set, private_handler);
96 DATA_SET(linux_ioctl_handler_set, drm_handler);
97
98 struct handler_element
99 {
100 TAILQ_ENTRY(handler_element) list;
101 int (*func)(struct proc *, struct linux_ioctl_args *);
102 int low, high, span;
103 };
104
105 static TAILQ_HEAD(, handler_element) handlers =
106 TAILQ_HEAD_INITIALIZER(handlers);
107
108 static int
109 linux_ioctl_disk(struct proc *p, struct linux_ioctl_args *args)
110 {
111 struct file *fp = p->p_fd->fd_ofiles[args->fd];
112 int error;
113 struct disklabel dl;
114
115 switch (args->cmd & 0xffff) {
116 case LINUX_BLKGETSIZE:
117 error = fo_ioctl(fp, DIOCGDINFO, (caddr_t)&dl, p);
118 if (error)
119 return (error);
120 return (copyout(&(dl.d_secperunit), (caddr_t)args->arg,
121 sizeof(dl.d_secperunit)));
122 break;
123 }
124 return (ENOIOCTL);
125 }
126
127 /*
128 * termio related ioctls
129 */
130
131 struct linux_termio {
132 unsigned short c_iflag;
133 unsigned short c_oflag;
134 unsigned short c_cflag;
135 unsigned short c_lflag;
136 unsigned char c_line;
137 unsigned char c_cc[LINUX_NCC];
138 };
139
140 struct linux_termios {
141 unsigned int c_iflag;
142 unsigned int c_oflag;
143 unsigned int c_cflag;
144 unsigned int c_lflag;
145 #ifdef __alpha__
146 unsigned char c_cc[LINUX_NCCS];
147 unsigned char c_line;
148 unsigned int c_ispeed;
149 unsigned int c_ospeed;
150 #else
151 unsigned char c_line;
152 unsigned char c_cc[LINUX_NCCS];
153 #endif
154 };
155
156 struct linux_winsize {
157 unsigned short ws_row, ws_col;
158 unsigned short ws_xpixel, ws_ypixel;
159 };
160
161 static struct speedtab sptab[] = {
162 { B0, LINUX_B0 }, { B50, LINUX_B50 },
163 { B75, LINUX_B75 }, { B110, LINUX_B110 },
164 { B134, LINUX_B134 }, { B150, LINUX_B150 },
165 { B200, LINUX_B200 }, { B300, LINUX_B300 },
166 { B600, LINUX_B600 }, { B1200, LINUX_B1200 },
167 { B1800, LINUX_B1800 }, { B2400, LINUX_B2400 },
168 { B4800, LINUX_B4800 }, { B9600, LINUX_B9600 },
169 { B19200, LINUX_B19200 }, { B38400, LINUX_B38400 },
170 { B57600, LINUX_B57600 }, { B115200, LINUX_B115200 },
171 {-1, -1 }
172 };
173
174 struct linux_serial_struct {
175 int type;
176 int line;
177 int port;
178 int irq;
179 int flags;
180 int xmit_fifo_size;
181 int custom_divisor;
182 int baud_base;
183 unsigned short close_delay;
184 char reserved_char[2];
185 int hub6;
186 unsigned short closing_wait;
187 unsigned short closing_wait2;
188 int reserved[4];
189 };
190
191 static int
192 linux_to_bsd_speed(int code, struct speedtab *table)
193 {
194 for ( ; table->sp_code != -1; table++)
195 if (table->sp_code == code)
196 return (table->sp_speed);
197 return -1;
198 }
199
200 static int
201 bsd_to_linux_speed(int speed, struct speedtab *table)
202 {
203 for ( ; table->sp_speed != -1; table++)
204 if (table->sp_speed == speed)
205 return (table->sp_code);
206 return -1;
207 }
208
209 static void
210 bsd_to_linux_termios(struct termios *bios, struct linux_termios *lios)
211 {
212 int i;
213
214 #ifdef DEBUG
215 if (ldebug(ioctl)) {
216 printf("LINUX: BSD termios structure (input):\n");
217 printf("i=%08x o=%08x c=%08x l=%08x ispeed=%d ospeed=%d\n",
218 bios->c_iflag, bios->c_oflag, bios->c_cflag, bios->c_lflag,
219 bios->c_ispeed, bios->c_ospeed);
220 printf("c_cc ");
221 for (i=0; i<NCCS; i++)
222 printf("%02x ", bios->c_cc[i]);
223 printf("\n");
224 }
225 #endif
226
227 lios->c_iflag = 0;
228 if (bios->c_iflag & IGNBRK)
229 lios->c_iflag |= LINUX_IGNBRK;
230 if (bios->c_iflag & BRKINT)
231 lios->c_iflag |= LINUX_BRKINT;
232 if (bios->c_iflag & IGNPAR)
233 lios->c_iflag |= LINUX_IGNPAR;
234 if (bios->c_iflag & PARMRK)
235 lios->c_iflag |= LINUX_PARMRK;
236 if (bios->c_iflag & INPCK)
237 lios->c_iflag |= LINUX_INPCK;
238 if (bios->c_iflag & ISTRIP)
239 lios->c_iflag |= LINUX_ISTRIP;
240 if (bios->c_iflag & INLCR)
241 lios->c_iflag |= LINUX_INLCR;
242 if (bios->c_iflag & IGNCR)
243 lios->c_iflag |= LINUX_IGNCR;
244 if (bios->c_iflag & ICRNL)
245 lios->c_iflag |= LINUX_ICRNL;
246 if (bios->c_iflag & IXON)
247 lios->c_iflag |= LINUX_IXON;
248 if (bios->c_iflag & IXANY)
249 lios->c_iflag |= LINUX_IXANY;
250 if (bios->c_iflag & IXOFF)
251 lios->c_iflag |= LINUX_IXOFF;
252 if (bios->c_iflag & IMAXBEL)
253 lios->c_iflag |= LINUX_IMAXBEL;
254
255 lios->c_oflag = 0;
256 if (bios->c_oflag & OPOST)
257 lios->c_oflag |= LINUX_OPOST;
258 if (bios->c_oflag & ONLCR)
259 lios->c_oflag |= LINUX_ONLCR;
260 if (bios->c_oflag & OXTABS)
261 lios->c_oflag |= LINUX_XTABS;
262
263 lios->c_cflag = bsd_to_linux_speed(bios->c_ispeed, sptab);
264 lios->c_cflag |= (bios->c_cflag & CSIZE) >> 4;
265 if (bios->c_cflag & CSTOPB)
266 lios->c_cflag |= LINUX_CSTOPB;
267 if (bios->c_cflag & CREAD)
268 lios->c_cflag |= LINUX_CREAD;
269 if (bios->c_cflag & PARENB)
270 lios->c_cflag |= LINUX_PARENB;
271 if (bios->c_cflag & PARODD)
272 lios->c_cflag |= LINUX_PARODD;
273 if (bios->c_cflag & HUPCL)
274 lios->c_cflag |= LINUX_HUPCL;
275 if (bios->c_cflag & CLOCAL)
276 lios->c_cflag |= LINUX_CLOCAL;
277 if (bios->c_cflag & CRTSCTS)
278 lios->c_cflag |= LINUX_CRTSCTS;
279
280 lios->c_lflag = 0;
281 if (bios->c_lflag & ISIG)
282 lios->c_lflag |= LINUX_ISIG;
283 if (bios->c_lflag & ICANON)
284 lios->c_lflag |= LINUX_ICANON;
285 if (bios->c_lflag & ECHO)
286 lios->c_lflag |= LINUX_ECHO;
287 if (bios->c_lflag & ECHOE)
288 lios->c_lflag |= LINUX_ECHOE;
289 if (bios->c_lflag & ECHOK)
290 lios->c_lflag |= LINUX_ECHOK;
291 if (bios->c_lflag & ECHONL)
292 lios->c_lflag |= LINUX_ECHONL;
293 if (bios->c_lflag & NOFLSH)
294 lios->c_lflag |= LINUX_NOFLSH;
295 if (bios->c_lflag & TOSTOP)
296 lios->c_lflag |= LINUX_TOSTOP;
297 if (bios->c_lflag & ECHOCTL)
298 lios->c_lflag |= LINUX_ECHOCTL;
299 if (bios->c_lflag & ECHOPRT)
300 lios->c_lflag |= LINUX_ECHOPRT;
301 if (bios->c_lflag & ECHOKE)
302 lios->c_lflag |= LINUX_ECHOKE;
303 if (bios->c_lflag & FLUSHO)
304 lios->c_lflag |= LINUX_FLUSHO;
305 if (bios->c_lflag & PENDIN)
306 lios->c_lflag |= LINUX_PENDIN;
307 if (bios->c_lflag & IEXTEN)
308 lios->c_lflag |= LINUX_IEXTEN;
309
310 for (i=0; i<LINUX_NCCS; i++)
311 lios->c_cc[i] = LINUX_POSIX_VDISABLE;
312 lios->c_cc[LINUX_VINTR] = bios->c_cc[VINTR];
313 lios->c_cc[LINUX_VQUIT] = bios->c_cc[VQUIT];
314 lios->c_cc[LINUX_VERASE] = bios->c_cc[VERASE];
315 lios->c_cc[LINUX_VKILL] = bios->c_cc[VKILL];
316 lios->c_cc[LINUX_VEOF] = bios->c_cc[VEOF];
317 lios->c_cc[LINUX_VEOL] = bios->c_cc[VEOL];
318 lios->c_cc[LINUX_VMIN] = bios->c_cc[VMIN];
319 lios->c_cc[LINUX_VTIME] = bios->c_cc[VTIME];
320 lios->c_cc[LINUX_VEOL2] = bios->c_cc[VEOL2];
321 lios->c_cc[LINUX_VSUSP] = bios->c_cc[VSUSP];
322 lios->c_cc[LINUX_VSTART] = bios->c_cc[VSTART];
323 lios->c_cc[LINUX_VSTOP] = bios->c_cc[VSTOP];
324 lios->c_cc[LINUX_VREPRINT] = bios->c_cc[VREPRINT];
325 lios->c_cc[LINUX_VDISCARD] = bios->c_cc[VDISCARD];
326 lios->c_cc[LINUX_VWERASE] = bios->c_cc[VWERASE];
327 lios->c_cc[LINUX_VLNEXT] = bios->c_cc[VLNEXT];
328
329 for (i=0; i<LINUX_NCCS; i++) {
330 if (i != LINUX_VMIN && i != LINUX_VTIME &&
331 lios->c_cc[i] == _POSIX_VDISABLE)
332 lios->c_cc[i] = LINUX_POSIX_VDISABLE;
333 }
334 lios->c_line = 0;
335
336 #ifdef DEBUG
337 if (ldebug(ioctl)) {
338 printf("LINUX: LINUX termios structure (output):\n");
339 printf("i=%08x o=%08x c=%08x l=%08x line=%d\n",
340 lios->c_iflag, lios->c_oflag, lios->c_cflag,
341 lios->c_lflag, (int)lios->c_line);
342 printf("c_cc ");
343 for (i=0; i<LINUX_NCCS; i++)
344 printf("%02x ", lios->c_cc[i]);
345 printf("\n");
346 }
347 #endif
348 }
349
350 static void
351 linux_to_bsd_termios(struct linux_termios *lios, struct termios *bios)
352 {
353 int i;
354
355 #ifdef DEBUG
356 if (ldebug(ioctl)) {
357 printf("LINUX: LINUX termios structure (input):\n");
358 printf("i=%08x o=%08x c=%08x l=%08x line=%d\n",
359 lios->c_iflag, lios->c_oflag, lios->c_cflag,
360 lios->c_lflag, (int)lios->c_line);
361 printf("c_cc ");
362 for (i=0; i<LINUX_NCCS; i++)
363 printf("%02x ", lios->c_cc[i]);
364 printf("\n");
365 }
366 #endif
367
368 bios->c_iflag = 0;
369 if (lios->c_iflag & LINUX_IGNBRK)
370 bios->c_iflag |= IGNBRK;
371 if (lios->c_iflag & LINUX_BRKINT)
372 bios->c_iflag |= BRKINT;
373 if (lios->c_iflag & LINUX_IGNPAR)
374 bios->c_iflag |= IGNPAR;
375 if (lios->c_iflag & LINUX_PARMRK)
376 bios->c_iflag |= PARMRK;
377 if (lios->c_iflag & LINUX_INPCK)
378 bios->c_iflag |= INPCK;
379 if (lios->c_iflag & LINUX_ISTRIP)
380 bios->c_iflag |= ISTRIP;
381 if (lios->c_iflag & LINUX_INLCR)
382 bios->c_iflag |= INLCR;
383 if (lios->c_iflag & LINUX_IGNCR)
384 bios->c_iflag |= IGNCR;
385 if (lios->c_iflag & LINUX_ICRNL)
386 bios->c_iflag |= ICRNL;
387 if (lios->c_iflag & LINUX_IXON)
388 bios->c_iflag |= IXON;
389 if (lios->c_iflag & LINUX_IXANY)
390 bios->c_iflag |= IXANY;
391 if (lios->c_iflag & LINUX_IXOFF)
392 bios->c_iflag |= IXOFF;
393 if (lios->c_iflag & LINUX_IMAXBEL)
394 bios->c_iflag |= IMAXBEL;
395
396 bios->c_oflag = 0;
397 if (lios->c_oflag & LINUX_OPOST)
398 bios->c_oflag |= OPOST;
399 if (lios->c_oflag & LINUX_ONLCR)
400 bios->c_oflag |= ONLCR;
401 if (lios->c_oflag & LINUX_XTABS)
402 bios->c_oflag |= OXTABS;
403
404 bios->c_cflag = (lios->c_cflag & LINUX_CSIZE) << 4;
405 if (lios->c_cflag & LINUX_CSTOPB)
406 bios->c_cflag |= CSTOPB;
407 if (lios->c_cflag & LINUX_CREAD)
408 bios->c_cflag |= CREAD;
409 if (lios->c_cflag & LINUX_PARENB)
410 bios->c_cflag |= PARENB;
411 if (lios->c_cflag & LINUX_PARODD)
412 bios->c_cflag |= PARODD;
413 if (lios->c_cflag & LINUX_HUPCL)
414 bios->c_cflag |= HUPCL;
415 if (lios->c_cflag & LINUX_CLOCAL)
416 bios->c_cflag |= CLOCAL;
417 if (lios->c_cflag & LINUX_CRTSCTS)
418 bios->c_cflag |= CRTSCTS;
419
420 bios->c_lflag = 0;
421 if (lios->c_lflag & LINUX_ISIG)
422 bios->c_lflag |= ISIG;
423 if (lios->c_lflag & LINUX_ICANON)
424 bios->c_lflag |= ICANON;
425 if (lios->c_lflag & LINUX_ECHO)
426 bios->c_lflag |= ECHO;
427 if (lios->c_lflag & LINUX_ECHOE)
428 bios->c_lflag |= ECHOE;
429 if (lios->c_lflag & LINUX_ECHOK)
430 bios->c_lflag |= ECHOK;
431 if (lios->c_lflag & LINUX_ECHONL)
432 bios->c_lflag |= ECHONL;
433 if (lios->c_lflag & LINUX_NOFLSH)
434 bios->c_lflag |= NOFLSH;
435 if (lios->c_lflag & LINUX_TOSTOP)
436 bios->c_lflag |= TOSTOP;
437 if (lios->c_lflag & LINUX_ECHOCTL)
438 bios->c_lflag |= ECHOCTL;
439 if (lios->c_lflag & LINUX_ECHOPRT)
440 bios->c_lflag |= ECHOPRT;
441 if (lios->c_lflag & LINUX_ECHOKE)
442 bios->c_lflag |= ECHOKE;
443 if (lios->c_lflag & LINUX_FLUSHO)
444 bios->c_lflag |= FLUSHO;
445 if (lios->c_lflag & LINUX_PENDIN)
446 bios->c_lflag |= PENDIN;
447 if (lios->c_lflag & LINUX_IEXTEN)
448 bios->c_lflag |= IEXTEN;
449
450 for (i=0; i<NCCS; i++)
451 bios->c_cc[i] = _POSIX_VDISABLE;
452 bios->c_cc[VINTR] = lios->c_cc[LINUX_VINTR];
453 bios->c_cc[VQUIT] = lios->c_cc[LINUX_VQUIT];
454 bios->c_cc[VERASE] = lios->c_cc[LINUX_VERASE];
455 bios->c_cc[VKILL] = lios->c_cc[LINUX_VKILL];
456 bios->c_cc[VEOF] = lios->c_cc[LINUX_VEOF];
457 bios->c_cc[VEOL] = lios->c_cc[LINUX_VEOL];
458 bios->c_cc[VMIN] = lios->c_cc[LINUX_VMIN];
459 bios->c_cc[VTIME] = lios->c_cc[LINUX_VTIME];
460 bios->c_cc[VEOL2] = lios->c_cc[LINUX_VEOL2];
461 bios->c_cc[VSUSP] = lios->c_cc[LINUX_VSUSP];
462 bios->c_cc[VSTART] = lios->c_cc[LINUX_VSTART];
463 bios->c_cc[VSTOP] = lios->c_cc[LINUX_VSTOP];
464 bios->c_cc[VREPRINT] = lios->c_cc[LINUX_VREPRINT];
465 bios->c_cc[VDISCARD] = lios->c_cc[LINUX_VDISCARD];
466 bios->c_cc[VWERASE] = lios->c_cc[LINUX_VWERASE];
467 bios->c_cc[VLNEXT] = lios->c_cc[LINUX_VLNEXT];
468
469 for (i=0; i<NCCS; i++) {
470 if (i != VMIN && i != VTIME &&
471 bios->c_cc[i] == LINUX_POSIX_VDISABLE)
472 bios->c_cc[i] = _POSIX_VDISABLE;
473 }
474
475 bios->c_ispeed = bios->c_ospeed =
476 linux_to_bsd_speed(lios->c_cflag & LINUX_CBAUD, sptab);
477
478 #ifdef DEBUG
479 if (ldebug(ioctl)) {
480 printf("LINUX: BSD termios structure (output):\n");
481 printf("i=%08x o=%08x c=%08x l=%08x ispeed=%d ospeed=%d\n",
482 bios->c_iflag, bios->c_oflag, bios->c_cflag, bios->c_lflag,
483 bios->c_ispeed, bios->c_ospeed);
484 printf("c_cc ");
485 for (i=0; i<NCCS; i++)
486 printf("%02x ", bios->c_cc[i]);
487 printf("\n");
488 }
489 #endif
490 }
491
492 static void
493 bsd_to_linux_termio(struct termios *bios, struct linux_termio *lio)
494 {
495 struct linux_termios lios;
496
497 bsd_to_linux_termios(bios, &lios);
498 lio->c_iflag = lios.c_iflag;
499 lio->c_oflag = lios.c_oflag;
500 lio->c_cflag = lios.c_cflag;
501 lio->c_lflag = lios.c_lflag;
502 lio->c_line = lios.c_line;
503 #ifdef __alpha__
504 lio->c_cc[LINUX__VINTR] = lios.c_cc[LINUX_VINTR];
505 lio->c_cc[LINUX__VQUIT] = lios.c_cc[LINUX_VQUIT];
506 lio->c_cc[LINUX__VERASE] = lios.c_cc[LINUX_VERASE];
507 lio->c_cc[LINUX__VKILL] = lios.c_cc[LINUX_VKILL];
508 lio->c_cc[LINUX__VEOF] =
509 lios.c_cc[(lios.c_lflag & ICANON) ? LINUX_VEOF : LINUX_VMIN];
510 lio->c_cc[LINUX__VEOL] =
511 lios.c_cc[(lios.c_lflag & ICANON) ? LINUX_VEOL : LINUX_VTIME];
512 lio->c_cc[LINUX__VEOL2] = lios.c_cc[LINUX_VEOL2];
513 lio->c_cc[LINUX__VSWTC] = lios.c_cc[LINUX_VSWTC];
514 #else
515 memcpy(lio->c_cc, lios.c_cc, LINUX_NCC);
516 #endif
517 }
518
519 static void
520 linux_to_bsd_termio(struct linux_termio *lio, struct termios *bios)
521 {
522 struct linux_termios lios;
523 int i;
524
525 lios.c_iflag = lio->c_iflag;
526 lios.c_oflag = lio->c_oflag;
527 lios.c_cflag = lio->c_cflag;
528 lios.c_lflag = lio->c_lflag;
529 #ifdef __alpha__
530 for (i=0; i<LINUX_NCCS; i++)
531 lios.c_cc[i] = LINUX_POSIX_VDISABLE;
532 lios.c_cc[LINUX_VINTR] = lio->c_cc[LINUX__VINTR];
533 lios.c_cc[LINUX_VQUIT] = lio->c_cc[LINUX__VQUIT];
534 lios.c_cc[LINUX_VERASE] = lio->c_cc[LINUX__VERASE];
535 lios.c_cc[LINUX_VKILL] = lio->c_cc[LINUX__VKILL];
536 lios.c_cc[LINUX_VEOL2] = lio->c_cc[LINUX__VEOL2];
537 lios.c_cc[LINUX_VSWTC] = lio->c_cc[LINUX__VSWTC];
538 lios.c_cc[(lio->c_lflag & ICANON) ? LINUX_VEOF : LINUX_VMIN] =
539 lio->c_cc[LINUX__VEOF];
540 lios.c_cc[(lio->c_lflag & ICANON) ? LINUX_VEOL : LINUX_VTIME] =
541 lio->c_cc[LINUX__VEOL];
542 #else
543 for (i=LINUX_NCC; i<LINUX_NCCS; i++)
544 lios.c_cc[i] = LINUX_POSIX_VDISABLE;
545 memcpy(lios.c_cc, lio->c_cc, LINUX_NCC);
546 #endif
547 linux_to_bsd_termios(&lios, bios);
548 }
549
550 static int
551 linux_ioctl_termio(struct proc *p, struct linux_ioctl_args *args)
552 {
553 struct termios bios;
554 struct linux_termios lios;
555 struct linux_termio lio;
556 struct file *fp = p->p_fd->fd_ofiles[args->fd];
557 int error;
558
559 switch (args->cmd & 0xffff) {
560
561 case LINUX_TCGETS:
562 error = fo_ioctl(fp, TIOCGETA, (caddr_t)&bios, p);
563 if (error)
564 return (error);
565 bsd_to_linux_termios(&bios, &lios);
566 return copyout(&lios, (caddr_t)args->arg, sizeof(lios));
567
568 case LINUX_TCSETS:
569 error = copyin((caddr_t)args->arg, &lios, sizeof(lios));
570 if (error)
571 return (error);
572 linux_to_bsd_termios(&lios, &bios);
573 return (fo_ioctl(fp, TIOCSETA, (caddr_t)&bios, p));
574
575 case LINUX_TCSETSW:
576 error = copyin((caddr_t)args->arg, &lios, sizeof(lios));
577 if (error)
578 return (error);
579 linux_to_bsd_termios(&lios, &bios);
580 return (fo_ioctl(fp, TIOCSETAW, (caddr_t)&bios, p));
581
582 case LINUX_TCSETSF:
583 error = copyin((caddr_t)args->arg, &lios, sizeof(lios));
584 if (error)
585 return (error);
586 linux_to_bsd_termios(&lios, &bios);
587 return (fo_ioctl(fp, TIOCSETAF, (caddr_t)&bios, p));
588
589 case LINUX_TCGETA:
590 error = fo_ioctl(fp, TIOCGETA, (caddr_t)&bios, p);
591 if (error)
592 return (error);
593 bsd_to_linux_termio(&bios, &lio);
594 return (copyout(&lio, (caddr_t)args->arg, sizeof(lio)));
595
596 case LINUX_TCSETA:
597 error = copyin((caddr_t)args->arg, &lio, sizeof(lio));
598 if (error)
599 return (error);
600 linux_to_bsd_termio(&lio, &bios);
601 return (fo_ioctl(fp, TIOCSETA, (caddr_t)&bios, p));
602
603 case LINUX_TCSETAW:
604 error = copyin((caddr_t)args->arg, &lio, sizeof(lio));
605 if (error)
606 return (error);
607 linux_to_bsd_termio(&lio, &bios);
608 return (fo_ioctl(fp, TIOCSETAW, (caddr_t)&bios, p));
609
610 case LINUX_TCSETAF:
611 error = copyin((caddr_t)args->arg, &lio, sizeof(lio));
612 if (error)
613 return (error);
614 linux_to_bsd_termio(&lio, &bios);
615 return (fo_ioctl(fp, TIOCSETAF, (caddr_t)&bios, p));
616
617 /* LINUX_TCSBRK */
618
619 case LINUX_TCXONC: {
620 switch (args->arg) {
621 case LINUX_TCOOFF:
622 args->cmd = TIOCSTOP;
623 break;
624 case LINUX_TCOON:
625 args->cmd = TIOCSTART;
626 break;
627 case LINUX_TCIOFF:
628 case LINUX_TCION: {
629 int c;
630 struct write_args wr;
631 error = fo_ioctl(fp, TIOCGETA, (caddr_t)&bios, p);
632 if (error)
633 return (error);
634 c = (args->arg == LINUX_TCIOFF) ? VSTOP : VSTART;
635 c = bios.c_cc[c];
636 if (c != _POSIX_VDISABLE) {
637 wr.fd = args->fd;
638 wr.buf = &c;
639 wr.nbyte = sizeof(c);
640 return (write(p, &wr));
641 } else
642 return (0);
643 }
644 default:
645 return (EINVAL);
646 }
647 args->arg = 0;
648 return (ioctl(p, (struct ioctl_args *)args));
649 }
650
651 case LINUX_TCFLSH: {
652 args->cmd = TIOCFLUSH;
653 switch (args->arg) {
654 case LINUX_TCIFLUSH:
655 args->arg = FREAD;
656 break;
657 case LINUX_TCOFLUSH:
658 args->arg = FWRITE;
659 break;
660 case LINUX_TCIOFLUSH:
661 args->arg = FREAD | FWRITE;
662 break;
663 default:
664 return (EINVAL);
665 }
666 return (ioctl(p, (struct ioctl_args *)args));
667 }
668
669 case LINUX_TIOCEXCL:
670 args->cmd = TIOCEXCL;
671 return (ioctl(p, (struct ioctl_args *)args));
672
673 case LINUX_TIOCNXCL:
674 args->cmd = TIOCNXCL;
675 return (ioctl(p, (struct ioctl_args *)args));
676
677 /* LINUX_TIOCSCTTY */
678
679 case LINUX_TIOCGPGRP:
680 args->cmd = TIOCGPGRP;
681 return (ioctl(p, (struct ioctl_args *)args));
682
683 case LINUX_TIOCSPGRP:
684 args->cmd = TIOCSPGRP;
685 return (ioctl(p, (struct ioctl_args *)args));
686
687 /* LINUX_TIOCOUTQ */
688 /* LINUX_TIOCSTI */
689
690 case LINUX_TIOCGWINSZ:
691 args->cmd = TIOCGWINSZ;
692 return (ioctl(p, (struct ioctl_args *)args));
693
694 case LINUX_TIOCSWINSZ:
695 args->cmd = TIOCSWINSZ;
696 return (ioctl(p, (struct ioctl_args *)args));
697
698 case LINUX_TIOCMGET:
699 args->cmd = TIOCMGET;
700 return (ioctl(p, (struct ioctl_args *)args));
701
702 case LINUX_TIOCMBIS:
703 args->cmd = TIOCMBIS;
704 return (ioctl(p, (struct ioctl_args *)args));
705
706 case LINUX_TIOCMBIC:
707 args->cmd = TIOCMBIC;
708 return (ioctl(p, (struct ioctl_args *)args));
709
710 case LINUX_TIOCMSET:
711 args->cmd = TIOCMSET;
712 return (ioctl(p, (struct ioctl_args *)args));
713
714 /* TIOCGSOFTCAR */
715 /* TIOCSSOFTCAR */
716
717 case LINUX_FIONREAD: /* LINUX_TIOCINQ */
718 args->cmd = FIONREAD;
719 return (ioctl(p, (struct ioctl_args *)args));
720
721 /* LINUX_TIOCLINUX */
722
723 case LINUX_TIOCCONS:
724 args->cmd = TIOCCONS;
725 return (ioctl(p, (struct ioctl_args *)args));
726
727 case LINUX_TIOCGSERIAL: {
728 struct linux_serial_struct lss;
729 lss.type = LINUX_PORT_16550A;
730 lss.flags = 0;
731 lss.close_delay = 0;
732 return copyout(&lss, (caddr_t)args->arg, sizeof(lss));
733 }
734
735 case LINUX_TIOCSSERIAL: {
736 struct linux_serial_struct lss;
737 error = copyin((caddr_t)args->arg, &lss, sizeof(lss));
738 if (error)
739 return (error);
740 /* XXX - It really helps to have an implementation that
741 * does nothing. NOT!
742 */
743 return (0);
744 }
745
746 /* LINUX_TIOCPKT */
747
748 case LINUX_FIONBIO:
749 args->cmd = FIONBIO;
750 return (ioctl(p, (struct ioctl_args *)args));
751
752 case LINUX_TIOCNOTTY:
753 args->cmd = TIOCNOTTY;
754 return (ioctl(p, (struct ioctl_args *)args));
755
756 case LINUX_TIOCSETD: {
757 int line;
758 switch (args->arg) {
759 case LINUX_N_TTY:
760 line = TTYDISC;
761 break;
762 case LINUX_N_SLIP:
763 line = SLIPDISC;
764 break;
765 case LINUX_N_PPP:
766 line = PPPDISC;
767 break;
768 default:
769 return (EINVAL);
770 }
771 return (fo_ioctl(fp, TIOCSETD, (caddr_t)&line, p));
772 }
773
774 case LINUX_TIOCGETD: {
775 int linux_line;
776 int bsd_line = TTYDISC;
777 error = fo_ioctl(fp, TIOCGETD, (caddr_t)&bsd_line, p);
778 if (error)
779 return (error);
780 switch (bsd_line) {
781 case TTYDISC:
782 linux_line = LINUX_N_TTY;
783 break;
784 case SLIPDISC:
785 linux_line = LINUX_N_SLIP;
786 break;
787 case PPPDISC:
788 linux_line = LINUX_N_PPP;
789 break;
790 default:
791 return (EINVAL);
792 }
793 return (copyout(&linux_line, (caddr_t)args->arg, sizeof(int)));
794 }
795
796 /* LINUX_TCSBRKP */
797 /* LINUX_TIOCTTYGSTRUCT */
798
799 case LINUX_FIONCLEX:
800 args->cmd = FIONCLEX;
801 return (ioctl(p, (struct ioctl_args *)args));
802
803 case LINUX_FIOCLEX:
804 args->cmd = FIOCLEX;
805 return (ioctl(p, (struct ioctl_args *)args));
806
807 case LINUX_FIOASYNC:
808 args->cmd = FIOASYNC;
809 return (ioctl(p, (struct ioctl_args *)args));
810
811 /* LINUX_TIOCSERCONFIG */
812 /* LINUX_TIOCSERGWILD */
813 /* LINUX_TIOCSERSWILD */
814 /* LINUX_TIOCGLCKTRMIOS */
815 /* LINUX_TIOCSLCKTRMIOS */
816
817 }
818
819 return (ENOIOCTL);
820 }
821
822 /*
823 * CDROM related ioctls
824 */
825
826 struct linux_cdrom_msf
827 {
828 u_char cdmsf_min0;
829 u_char cdmsf_sec0;
830 u_char cdmsf_frame0;
831 u_char cdmsf_min1;
832 u_char cdmsf_sec1;
833 u_char cdmsf_frame1;
834 };
835
836 struct linux_cdrom_tochdr
837 {
838 u_char cdth_trk0;
839 u_char cdth_trk1;
840 };
841
842 union linux_cdrom_addr
843 {
844 struct {
845 u_char minute;
846 u_char second;
847 u_char frame;
848 } msf;
849 int lba;
850 };
851
852 struct linux_cdrom_tocentry
853 {
854 u_char cdte_track;
855 u_char cdte_adr:4;
856 u_char cdte_ctrl:4;
857 u_char cdte_format;
858 union linux_cdrom_addr cdte_addr;
859 u_char cdte_datamode;
860 };
861
862 struct linux_cdrom_subchnl
863 {
864 u_char cdsc_format;
865 u_char cdsc_audiostatus;
866 u_char cdsc_adr:4;
867 u_char cdsc_ctrl:4;
868 u_char cdsc_trk;
869 u_char cdsc_ind;
870 union linux_cdrom_addr cdsc_absaddr;
871 union linux_cdrom_addr cdsc_reladdr;
872 };
873
874 static void
875 bsd_to_linux_msf_lba(u_char af, union msf_lba *bp, union linux_cdrom_addr *lp)
876 {
877 if (af == CD_LBA_FORMAT)
878 lp->lba = bp->lba;
879 else {
880 lp->msf.minute = bp->msf.minute;
881 lp->msf.second = bp->msf.second;
882 lp->msf.frame = bp->msf.frame;
883 }
884 }
885
886 static void
887 set_linux_cdrom_addr(union linux_cdrom_addr *addr, int format, int lba)
888 {
889 if (format == LINUX_CDROM_MSF) {
890 addr->msf.frame = lba % 75;
891 lba /= 75;
892 lba += 2;
893 addr->msf.second = lba % 60;
894 addr->msf.minute = lba / 60;
895 } else
896 addr->lba = lba;
897 }
898
899 static int
900 linux_ioctl_cdrom(struct proc *p, struct linux_ioctl_args *args)
901 {
902 struct file *fp = p->p_fd->fd_ofiles[args->fd];
903 int error;
904
905 switch (args->cmd & 0xffff) {
906
907 case LINUX_CDROMPAUSE:
908 args->cmd = CDIOCPAUSE;
909 return (ioctl(p, (struct ioctl_args *)args));
910
911 case LINUX_CDROMRESUME:
912 args->cmd = CDIOCRESUME;
913 return (ioctl(p, (struct ioctl_args *)args));
914
915 case LINUX_CDROMPLAYMSF:
916 args->cmd = CDIOCPLAYMSF;
917 return (ioctl(p, (struct ioctl_args *)args));
918
919 case LINUX_CDROMPLAYTRKIND:
920 args->cmd = CDIOCPLAYTRACKS;
921 return (ioctl(p, (struct ioctl_args *)args));
922
923 case LINUX_CDROMREADTOCHDR: {
924 struct ioc_toc_header th;
925 struct linux_cdrom_tochdr lth;
926 error = fo_ioctl(fp, CDIOREADTOCHEADER, (caddr_t)&th, p);
927 if (!error) {
928 lth.cdth_trk0 = th.starting_track;
929 lth.cdth_trk1 = th.ending_track;
930 copyout(<h, (caddr_t)args->arg, sizeof(lth));
931 }
932 return (error);
933 }
934
935 case LINUX_CDROMREADTOCENTRY: {
936 struct linux_cdrom_tocentry lte;
937 struct ioc_read_toc_single_entry irtse;
938
939 error = copyin((caddr_t)args->arg, <e, sizeof(lte));
940 if (error)
941 return (error);
942 irtse.address_format = lte.cdte_format;
943 irtse.track = lte.cdte_track;
944 error = fo_ioctl(fp, CDIOREADTOCENTRY, (caddr_t)&irtse, p);
945 if (!error) {
946 lte.cdte_ctrl = irtse.entry.control;
947 lte.cdte_adr = irtse.entry.addr_type;
948 bsd_to_linux_msf_lba(irtse.address_format,
949 &irtse.entry.addr, <e.cdte_addr);
950 error = copyout(<e, (caddr_t)args->arg, sizeof(lte));
951 }
952 return (error);
953 }
954
955 case LINUX_CDROMSTOP:
956 args->cmd = CDIOCSTOP;
957 return (ioctl(p, (struct ioctl_args *)args));
958
959 case LINUX_CDROMSTART:
960 args->cmd = CDIOCSTART;
961 return (ioctl(p, (struct ioctl_args *)args));
962
963 case LINUX_CDROMEJECT:
964 args->cmd = CDIOCEJECT;
965 return (ioctl(p, (struct ioctl_args *)args));
966
967 /* LINUX_CDROMVOLCTRL */
968
969 case LINUX_CDROMSUBCHNL: {
970 struct linux_cdrom_subchnl sc;
971 struct ioc_read_subchannel bsdsc;
972 struct cd_sub_channel_info *bsdinfo;
973 caddr_t sg = stackgap_init();
974 bsdinfo = (struct cd_sub_channel_info*)stackgap_alloc(&sg,
975 sizeof(struct cd_sub_channel_info));
976 bsdsc.address_format = CD_LBA_FORMAT;
977 bsdsc.data_format = CD_CURRENT_POSITION;
978 bsdsc.track = 0;
979 bsdsc.data_len = sizeof(struct cd_sub_channel_info);
980 bsdsc.data = bsdinfo;
981 error = fo_ioctl(fp, CDIOCREADSUBCHANNEL, (caddr_t)&bsdsc, p);
982 if (error)
983 return (error);
984 error = copyin((caddr_t)args->arg, &sc,
985 sizeof(struct linux_cdrom_subchnl));
986 if (error)
987 return (error);
988 sc.cdsc_audiostatus = bsdinfo->header.audio_status;
989 sc.cdsc_adr = bsdinfo->what.position.addr_type;
990 sc.cdsc_ctrl = bsdinfo->what.position.control;
991 sc.cdsc_trk = bsdinfo->what.position.track_number;
992 sc.cdsc_ind = bsdinfo->what.position.index_number;
993 set_linux_cdrom_addr(&sc.cdsc_absaddr, sc.cdsc_format,
994 bsdinfo->what.position.absaddr.lba);
995 set_linux_cdrom_addr(&sc.cdsc_reladdr, sc.cdsc_format,
996 bsdinfo->what.position.reladdr.lba);
997 error = copyout(&sc, (caddr_t)args->arg,
998 sizeof(struct linux_cdrom_subchnl));
999 return (error);
1000 }
1001
1002 /* LINUX_CDROMREADMODE2 */
1003 /* LINUX_CDROMREADMODE1 */
1004 /* LINUX_CDROMREADAUDIO */
1005 /* LINUX_CDROMEJECT_SW */
1006 /* LINUX_CDROMMULTISESSION */
1007 /* LINUX_CDROM_GET_UPC */
1008
1009 case LINUX_CDROMRESET:
1010 args->cmd = CDIOCRESET;
1011 return (ioctl(p, (struct ioctl_args *)args));
1012
1013 /* LINUX_CDROMVOLREAD */
1014 /* LINUX_CDROMREADRAW */
1015 /* LINUX_CDROMREADCOOKED */
1016 /* LINUX_CDROMSEEK */
1017 /* LINUX_CDROMPLAYBLK */
1018 /* LINUX_CDROMREADALL */
1019 /* LINUX_CDROMCLOSETRAY */
1020 /* LINUX_CDROMLOADFROMSLOT */
1021
1022 }
1023
1024 return (ENOIOCTL);
1025 }
1026
1027 /*
1028 * Sound related ioctls
1029 */
1030
1031 static u_int32_t dirbits[4] = { IOC_VOID, IOC_IN, IOC_OUT, IOC_INOUT };
1032
1033 #define SETDIR(c) (((c) & ~IOC_DIRMASK) | dirbits[args->cmd >> 30])
1034
1035 static int
1036 linux_ioctl_sound(struct proc *p, struct linux_ioctl_args *args)
1037 {
1038
1039 switch (args->cmd & 0xffff) {
1040
1041 case LINUX_SOUND_MIXER_WRITE_VOLUME:
1042 args->cmd = SETDIR(SOUND_MIXER_WRITE_VOLUME);
1043 return (ioctl(p, (struct ioctl_args *)args));
1044
1045 case LINUX_SOUND_MIXER_WRITE_BASS:
1046 args->cmd = SETDIR(SOUND_MIXER_WRITE_BASS);
1047 return (ioctl(p, (struct ioctl_args *)args));
1048
1049 case LINUX_SOUND_MIXER_WRITE_TREBLE:
1050 args->cmd = SETDIR(SOUND_MIXER_WRITE_TREBLE);
1051 return (ioctl(p, (struct ioctl_args *)args));
1052
1053 case LINUX_SOUND_MIXER_WRITE_SYNTH:
1054 args->cmd = SETDIR(SOUND_MIXER_WRITE_SYNTH);
1055 return (ioctl(p, (struct ioctl_args *)args));
1056
1057 case LINUX_SOUND_MIXER_WRITE_PCM:
1058 args->cmd = SETDIR(SOUND_MIXER_WRITE_PCM);
1059 return (ioctl(p, (struct ioctl_args *)args));
1060
1061 case LINUX_SOUND_MIXER_WRITE_SPEAKER:
1062 args->cmd = SETDIR(SOUND_MIXER_WRITE_SPEAKER);
1063 return (ioctl(p, (struct ioctl_args *)args));
1064
1065 case LINUX_SOUND_MIXER_WRITE_LINE:
1066 args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE);
1067 return (ioctl(p, (struct ioctl_args *)args));
1068
1069 case LINUX_SOUND_MIXER_WRITE_MIC:
1070 args->cmd = SETDIR(SOUND_MIXER_WRITE_MIC);
1071 return (ioctl(p, (struct ioctl_args *)args));
1072
1073 case LINUX_SOUND_MIXER_WRITE_CD:
1074 args->cmd = SETDIR(SOUND_MIXER_WRITE_CD);
1075 return (ioctl(p, (struct ioctl_args *)args));
1076
1077 case LINUX_SOUND_MIXER_WRITE_IMIX:
1078 args->cmd = SETDIR(SOUND_MIXER_WRITE_IMIX);
1079 return (ioctl(p, (struct ioctl_args *)args));
1080
1081 case LINUX_SOUND_MIXER_WRITE_ALTPCM:
1082 args->cmd = SETDIR(SOUND_MIXER_WRITE_ALTPCM);
1083 return (ioctl(p, (struct ioctl_args *)args));
1084
1085 case LINUX_SOUND_MIXER_WRITE_RECLEV:
1086 args->cmd = SETDIR(SOUND_MIXER_WRITE_RECLEV);
1087 return (ioctl(p, (struct ioctl_args *)args));
1088
1089 case LINUX_SOUND_MIXER_WRITE_IGAIN:
1090 args->cmd = SETDIR(SOUND_MIXER_WRITE_IGAIN);
1091 return (ioctl(p, (struct ioctl_args *)args));
1092
1093 case LINUX_SOUND_MIXER_WRITE_OGAIN:
1094 args->cmd = SETDIR(SOUND_MIXER_WRITE_OGAIN);
1095 return (ioctl(p, (struct ioctl_args *)args));
1096
1097 case LINUX_SOUND_MIXER_WRITE_LINE1:
1098 args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE1);
1099 return (ioctl(p, (struct ioctl_args *)args));
1100
1101 case LINUX_SOUND_MIXER_WRITE_LINE2:
1102 args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE2);
1103 return (ioctl(p, (struct ioctl_args *)args));
1104
1105 case LINUX_SOUND_MIXER_WRITE_LINE3:
1106 args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE3);
1107 return (ioctl(p, (struct ioctl_args *)args));
1108
1109 case LINUX_OSS_GETVERSION: {
1110 int version = linux_get_oss_version(p);
1111 return (copyout(&version, (caddr_t)args->arg, sizeof(int)));
1112 }
1113
1114 case LINUX_SOUND_MIXER_READ_DEVMASK:
1115 args->cmd = SOUND_MIXER_READ_DEVMASK;
1116 return (ioctl(p, (struct ioctl_args *)args));
1117
1118 case LINUX_SOUND_MIXER_WRITE_RECSRC:
1119 args->cmd = SETDIR(SOUND_MIXER_WRITE_RECSRC);
1120 return (ioctl(p, (struct ioctl_args *)args));
1121
1122 case LINUX_SNDCTL_DSP_RESET:
1123 args->cmd = SNDCTL_DSP_RESET;
1124 return (ioctl(p, (struct ioctl_args *)args));
1125
1126 case LINUX_SNDCTL_DSP_SYNC:
1127 args->cmd = SNDCTL_DSP_SYNC;
1128 return (ioctl(p, (struct ioctl_args *)args));
1129
1130 case LINUX_SNDCTL_DSP_SPEED:
1131 args->cmd = SNDCTL_DSP_SPEED;
1132 return (ioctl(p, (struct ioctl_args *)args));
1133
1134 case LINUX_SNDCTL_DSP_STEREO:
1135 args->cmd = SNDCTL_DSP_STEREO;
1136 return (ioctl(p, (struct ioctl_args *)args));
1137
1138 case LINUX_SNDCTL_DSP_GETBLKSIZE: /* LINUX_SNDCTL_DSP_SETBLKSIZE */
1139 args->cmd = SNDCTL_DSP_GETBLKSIZE;
1140 return (ioctl(p, (struct ioctl_args *)args));
1141
1142 case LINUX_SNDCTL_DSP_SETFMT:
1143 args->cmd = SNDCTL_DSP_SETFMT;
1144 return (ioctl(p, (struct ioctl_args *)args));
1145
1146 case LINUX_SOUND_PCM_WRITE_CHANNELS:
1147 args->cmd = SOUND_PCM_WRITE_CHANNELS;
1148 return (ioctl(p, (struct ioctl_args *)args));
1149
1150 case LINUX_SOUND_PCM_WRITE_FILTER:
1151 args->cmd = SOUND_PCM_WRITE_FILTER;
1152 return (ioctl(p, (struct ioctl_args *)args));
1153
1154 case LINUX_SNDCTL_DSP_POST:
1155 args->cmd = SNDCTL_DSP_POST;
1156 return (ioctl(p, (struct ioctl_args *)args));
1157
1158 case LINUX_SNDCTL_DSP_SUBDIVIDE:
1159 args->cmd = SNDCTL_DSP_SUBDIVIDE;
1160 return (ioctl(p, (struct ioctl_args *)args));
1161
1162 case LINUX_SNDCTL_DSP_SETFRAGMENT:
1163 args->cmd = SNDCTL_DSP_SETFRAGMENT;
1164 return (ioctl(p, (struct ioctl_args *)args));
1165
1166 case LINUX_SNDCTL_DSP_GETFMTS:
1167 args->cmd = SNDCTL_DSP_GETFMTS;
1168 return (ioctl(p, (struct ioctl_args *)args));
1169
1170 case LINUX_SNDCTL_DSP_GETOSPACE:
1171 args->cmd = SNDCTL_DSP_GETOSPACE;
1172 return (ioctl(p, (struct ioctl_args *)args));
1173
1174 case LINUX_SNDCTL_DSP_GETISPACE:
1175 args->cmd = SNDCTL_DSP_GETISPACE;
1176 return (ioctl(p, (struct ioctl_args *)args));
1177
1178 case LINUX_SNDCTL_DSP_NONBLOCK:
1179 args->cmd = SNDCTL_DSP_NONBLOCK;
1180 return (ioctl(p, (struct ioctl_args *)args));
1181
1182 case LINUX_SNDCTL_DSP_GETCAPS:
1183 args->cmd = SNDCTL_DSP_GETCAPS;
1184 return (ioctl(p, (struct ioctl_args *)args));
1185
1186 case LINUX_SNDCTL_DSP_SETTRIGGER: /* LINUX_SNDCTL_GETTRIGGER */
1187 args->cmd = SNDCTL_DSP_SETTRIGGER;
1188 return (ioctl(p, (struct ioctl_args *)args));
1189
1190 case LINUX_SNDCTL_DSP_GETIPTR:
1191 args->cmd = SNDCTL_DSP_GETIPTR;
1192 return (ioctl(p, (struct ioctl_args *)args));
1193
1194 case LINUX_SNDCTL_DSP_GETOPTR:
1195 args->cmd = SNDCTL_DSP_GETOPTR;
1196 return (ioctl(p, (struct ioctl_args *)args));
1197
1198 case LINUX_SNDCTL_DSP_GETODELAY:
1199 args->cmd = SNDCTL_DSP_GETODELAY;
1200 return (ioctl(p, (struct ioctl_args *)args));
1201
1202 case LINUX_SNDCTL_SEQ_RESET:
1203 args->cmd = SNDCTL_SEQ_RESET;
1204 return (ioctl(p, (struct ioctl_args *)args));
1205
1206 case LINUX_SNDCTL_SEQ_SYNC:
1207 args->cmd = SNDCTL_SEQ_SYNC;
1208 return (ioctl(p, (struct ioctl_args *)args));
1209
1210 case LINUX_SNDCTL_SYNTH_INFO:
1211 args->cmd = SNDCTL_SYNTH_INFO;
1212 return (ioctl(p, (struct ioctl_args *)args));
1213
1214 case LINUX_SNDCTL_SEQ_CTRLRATE:
1215 args->cmd = SNDCTL_SEQ_CTRLRATE;
1216 return (ioctl(p, (struct ioctl_args *)args));
1217
1218 case LINUX_SNDCTL_SEQ_GETOUTCOUNT:
1219 args->cmd = SNDCTL_SEQ_GETOUTCOUNT;
1220 return (ioctl(p, (struct ioctl_args *)args));
1221
1222 case LINUX_SNDCTL_SEQ_GETINCOUNT:
1223 args->cmd = SNDCTL_SEQ_GETINCOUNT;
1224 return (ioctl(p, (struct ioctl_args *)args));
1225
1226 case LINUX_SNDCTL_SEQ_PERCMODE:
1227 args->cmd = SNDCTL_SEQ_PERCMODE;
1228 return (ioctl(p, (struct ioctl_args *)args));
1229
1230 case LINUX_SNDCTL_FM_LOAD_INSTR:
1231 args->cmd = SNDCTL_FM_LOAD_INSTR;
1232 return (ioctl(p, (struct ioctl_args *)args));
1233
1234 case LINUX_SNDCTL_SEQ_TESTMIDI:
1235 args->cmd = SNDCTL_SEQ_TESTMIDI;
1236 return (ioctl(p, (struct ioctl_args *)args));
1237
1238 case LINUX_SNDCTL_SEQ_RESETSAMPLES:
1239 args->cmd = SNDCTL_SEQ_RESETSAMPLES;
1240 return (ioctl(p, (struct ioctl_args *)args));
1241
1242 case LINUX_SNDCTL_SEQ_NRSYNTHS:
1243 args->cmd = SNDCTL_SEQ_NRSYNTHS;
1244 return (ioctl(p, (struct ioctl_args *)args));
1245
1246 case LINUX_SNDCTL_SEQ_NRMIDIS:
1247 args->cmd = SNDCTL_SEQ_NRMIDIS;
1248 return (ioctl(p, (struct ioctl_args *)args));
1249
1250 case LINUX_SNDCTL_MIDI_INFO:
1251 args->cmd = SNDCTL_MIDI_INFO;
1252 return (ioctl(p, (struct ioctl_args *)args));
1253
1254 case LINUX_SNDCTL_SEQ_TRESHOLD:
1255 args->cmd = SNDCTL_SEQ_TRESHOLD;
1256 return (ioctl(p, (struct ioctl_args *)args));
1257
1258 case LINUX_SNDCTL_SYNTH_MEMAVL:
1259 args->cmd = SNDCTL_SYNTH_MEMAVL;
1260 return (ioctl(p, (struct ioctl_args *)args));
1261
1262 }
1263
1264 return (ENOIOCTL);
1265 }
1266
1267 /*
1268 * Console related ioctls
1269 */
1270
1271 #define ISSIGVALID(sig) ((sig) > 0 && (sig) < NSIG)
1272
1273 static int
1274 linux_ioctl_console(struct proc *p, struct linux_ioctl_args *args)
1275 {
1276 struct file *fp = p->p_fd->fd_ofiles[args->fd];
1277 int error;
1278
1279 switch (args->cmd & 0xffff) {
1280
1281 case LINUX_KIOCSOUND:
1282 args->cmd = KIOCSOUND;
1283 return (ioctl(p, (struct ioctl_args *)args));
1284
1285 case LINUX_KDMKTONE:
1286 args->cmd = KDMKTONE;
1287 return (ioctl(p, (struct ioctl_args *)args));
1288
1289 case LINUX_KDGETLED:
1290 args->cmd = KDGETLED;
1291 return (ioctl(p, (struct ioctl_args *)args));
1292
1293 case LINUX_KDSETLED:
1294 args->cmd = KDSETLED;
1295 return (ioctl(p, (struct ioctl_args *)args));
1296
1297 case LINUX_KDSETMODE:
1298 args->cmd = KDSETMODE;
1299 return (ioctl(p, (struct ioctl_args *)args));
1300
1301 case LINUX_KDGETMODE:
1302 args->cmd = KDGETMODE;
1303 return (ioctl(p, (struct ioctl_args *)args));
1304
1305 case LINUX_KDGKBMODE:
1306 args->cmd = KDGKBMODE;
1307 return (ioctl(p, (struct ioctl_args *)args));
1308
1309 case LINUX_KDSKBMODE: {
1310 int kbdmode;
1311 switch (args->arg) {
1312 case LINUX_KBD_RAW:
1313 kbdmode = K_RAW;
1314 break;
1315 case LINUX_KBD_XLATE:
1316 kbdmode = K_XLATE;
1317 break;
1318 case LINUX_KBD_MEDIUMRAW:
1319 kbdmode = K_RAW;
1320 break;
1321 default:
1322 return (EINVAL);
1323 }
1324 return (fo_ioctl(fp, KDSKBMODE, (caddr_t)&kbdmode, p));
1325 }
1326
1327 case LINUX_VT_OPENQRY:
1328 args->cmd = VT_OPENQRY;
1329 return (ioctl(p, (struct ioctl_args *)args));
1330
1331 case LINUX_VT_GETMODE:
1332 args->cmd = VT_GETMODE;
1333 return (ioctl(p, (struct ioctl_args *)args));
1334
1335 case LINUX_VT_SETMODE: {
1336 struct vt_mode mode;
1337 error = copyin((caddr_t)args->arg, &mode, sizeof(mode));
1338 if (error)
1339 return (error);
1340 if (!ISSIGVALID(mode.frsig) && ISSIGVALID(mode.acqsig))
1341 mode.frsig = mode.acqsig;
1342 error = copyout(&mode, (caddr_t)args->arg, sizeof(mode));
1343 if (error)
1344 return (error);
1345 args->cmd = VT_SETMODE;
1346 return (ioctl(p, (struct ioctl_args *)args));
1347 }
1348
1349 case LINUX_VT_GETSTATE:
1350 args->cmd = VT_GETACTIVE;
1351 return (ioctl(p, (struct ioctl_args *)args));
1352
1353 case LINUX_VT_RELDISP:
1354 args->cmd = VT_RELDISP;
1355 return (ioctl(p, (struct ioctl_args *)args));
1356
1357 case LINUX_VT_ACTIVATE:
1358 args->cmd = VT_ACTIVATE;
1359 return (ioctl(p, (struct ioctl_args *)args));
1360
1361 case LINUX_VT_WAITACTIVE:
1362 args->cmd = VT_WAITACTIVE;
1363 return (ioctl(p, (struct ioctl_args *)args));
1364
1365 }
1366
1367 return (ENOIOCTL);
1368 }
1369
1370 /*
1371 * Criteria for interface name translation
1372 */
1373 #define IFP_IS_ETH(ifp) (ifp->if_type == IFT_ETHER)
1374
1375 /*
1376 * Interface function used by linprocfs (at the time of writing). It's not
1377 * used by the Linuxulator itself.
1378 */
1379 int
1380 linux_ifname(struct ifnet *ifp, char *buffer, size_t buflen)
1381 {
1382 struct ifnet *ifscan;
1383 int ethno;
1384
1385 /* Short-circuit non ethernet interfaces */
1386 if (!IFP_IS_ETH(ifp))
1387 return (snprintf(buffer, buflen, "%s%d", ifp->if_name,
1388 ifp->if_unit));
1389
1390 /* Determine the (relative) unit number for ethernet interfaces */
1391 ethno = 0;
1392 TAILQ_FOREACH(ifscan, &ifnet, if_link) {
1393 if (ifscan == ifp)
1394 return (snprintf(buffer, buflen, "eth%d", ethno));
1395 if (IFP_IS_ETH(ifscan))
1396 ethno++;
1397 }
1398
1399 return (0);
1400 }
1401
1402 /*
1403 * Translate a Linux interface name to a FreeBSD interface name,
1404 * and return the associated ifnet structure
1405 * bsdname and lxname need to be least IFNAMSIZ bytes long, but
1406 * can point to the same buffer.
1407 */
1408
1409 static struct ifnet *
1410 ifname_linux_to_bsd(const char *lxname, char *bsdname)
1411 {
1412 struct ifnet *ifp;
1413 int len, unit;
1414 char *ep;
1415 int is_eth, index;
1416
1417 for (len = 0; len < LINUX_IFNAMSIZ; ++len)
1418 if (!isalpha(lxname[len]))
1419 break;
1420 if (len == 0 || len == LINUX_IFNAMSIZ)
1421 return (NULL);
1422 unit = (int)strtoul(lxname + len, &ep, 10);
1423 if (ep == NULL || ep == lxname + len || ep >= lxname + LINUX_IFNAMSIZ)
1424 return (NULL);
1425 index = 0;
1426 is_eth = (len == 3 && !strncmp(lxname, "eth", len)) ? 1 : 0;
1427 TAILQ_FOREACH(ifp, &ifnet, if_link) {
1428 /*
1429 * Allow Linux programs to use FreeBSD names. Don't presume
1430 * we never have an interface named "eth", so don't make
1431 * the test optional based on is_eth.
1432 */
1433 if (ifp->if_unit == unit && ifp->if_name[len] == '\0' &&
1434 strncmp(ifp->if_name, lxname, len) == 0)
1435 break;
1436 if (is_eth && IFP_IS_ETH(ifp) && unit == index++)
1437 break;
1438 }
1439 if (ifp != NULL)
1440 snprintf(bsdname, IFNAMSIZ, "%s%d", ifp->if_name, ifp->if_unit);
1441 return (ifp);
1442 }
1443
1444 /*
1445 * Implement the SIOCGIFCONF ioctl
1446 */
1447
1448 static int
1449 linux_ifconf(struct proc *p, struct ifconf *uifc)
1450 {
1451 struct ifconf ifc;
1452 struct l_ifreq ifr;
1453 struct ifnet *ifp;
1454 struct ifaddr *ifa;
1455 struct iovec iov;
1456 struct uio uio;
1457 int error, ethno;
1458
1459 error = copyin(uifc, &ifc, sizeof ifc);
1460 if (error != 0)
1461 return (error);
1462
1463 /* much easier to use uiomove than keep track ourselves */
1464 iov.iov_base = ifc.ifc_buf;
1465 iov.iov_len = ifc.ifc_len;
1466 uio.uio_iov = &iov;
1467 uio.uio_iovcnt = 1;
1468 uio.uio_offset = 0;
1469 uio.uio_resid = ifc.ifc_len;
1470 uio.uio_segflg = UIO_USERSPACE;
1471 uio.uio_rw = UIO_READ;
1472 uio.uio_procp = p;
1473
1474 /* Keep track of eth interfaces */
1475 ethno = 0;
1476
1477 /* Return all AF_INET addresses of all interfaces */
1478 TAILQ_FOREACH(ifp, &ifnet, if_link) {
1479 if (uio.uio_resid <= 0)
1480 break;
1481
1482 bzero(&ifr, sizeof ifr);
1483 if (IFP_IS_ETH(ifp))
1484 snprintf(ifr.ifr_name, LINUX_IFNAMSIZ, "eth%d",
1485 ethno++);
1486 else
1487 snprintf(ifr.ifr_name, LINUX_IFNAMSIZ, "%s%d",
1488 ifp->if_name, ifp->if_unit);
1489
1490 /* Walk the address list */
1491 TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
1492 struct sockaddr *sa = ifa->ifa_addr;
1493
1494 if (uio.uio_resid <= 0)
1495 break;
1496
1497 if (sa->sa_family == AF_INET) {
1498 ifr.ifr_addr.sa_family = LINUX_AF_INET;
1499 memcpy(ifr.ifr_addr.sa_data, sa->sa_data,
1500 sizeof(ifr.ifr_addr.sa_data));
1501
1502 error = uiomove((caddr_t)&ifr, sizeof ifr,
1503 &uio);
1504 if (error != 0)
1505 return (error);
1506 }
1507 }
1508 }
1509
1510 ifc.ifc_len -= uio.uio_resid;
1511 error = copyout(&ifc, uifc, sizeof ifc);
1512
1513 return (error);
1514 }
1515
1516 static int
1517 linux_gifflags(struct proc *p, struct ifnet *ifp, struct l_ifreq *ifr)
1518 {
1519 l_short flags;
1520
1521 flags = ifp->if_flags;
1522 /* these flags have no Linux equivalent */
1523 flags &= ~(IFF_SMART|IFF_OACTIVE|IFF_SIMPLEX|
1524 IFF_LINK0|IFF_LINK1|IFF_LINK2);
1525 /* Linux' multicast flag is in a different bit */
1526 if (flags & IFF_MULTICAST) {
1527 flags &= ~IFF_MULTICAST;
1528 flags |= 0x1000;
1529 }
1530
1531 return (copyout(&flags, &ifr->ifr_flags, sizeof flags));
1532 }
1533
1534 #define ARPHRD_ETHER 1
1535 #define ARPHRD_LOOPBACK 772
1536
1537 static int
1538 linux_gifhwaddr(struct ifnet *ifp, struct l_ifreq *ifr)
1539 {
1540 struct ifaddr *ifa;
1541 struct sockaddr_dl *sdl;
1542 struct l_sockaddr lsa;
1543
1544 if (ifp->if_type == IFT_LOOP) {
1545 bzero(&lsa, sizeof lsa);
1546 lsa.sa_family = ARPHRD_LOOPBACK;
1547 return (copyout(&lsa, &ifr->ifr_hwaddr, sizeof lsa));
1548 }
1549
1550 if (ifp->if_type != IFT_ETHER)
1551 return (ENOENT);
1552
1553 TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
1554 sdl = (struct sockaddr_dl*)ifa->ifa_addr;
1555 if (sdl != NULL && (sdl->sdl_family == AF_LINK) &&
1556 (sdl->sdl_type == IFT_ETHER)) {
1557 bzero(&lsa, sizeof lsa);
1558 lsa.sa_family = ARPHRD_ETHER;
1559 bcopy(LLADDR(sdl), lsa.sa_data, LINUX_IFHWADDRLEN);
1560 return (copyout(&lsa, &ifr->ifr_hwaddr, sizeof lsa));
1561 }
1562 }
1563
1564 return (ENOENT);
1565 }
1566
1567 /*
1568 * Socket related ioctls
1569 */
1570
1571 static int
1572 linux_ioctl_socket(struct proc *p, struct linux_ioctl_args *args)
1573 {
1574 char lifname[LINUX_IFNAMSIZ], ifname[IFNAMSIZ];
1575 struct ifnet *ifp;
1576 struct file *fp;
1577 int error, type;
1578
1579 KASSERT(LINUX_IFNAMSIZ == IFNAMSIZ,
1580 (__FUNCTION__ "(): LINUX_IFNAMSIZ != IFNAMSIZ"));
1581
1582 ifp = NULL;
1583 error = 0;
1584
1585 if (args->fd >= p->p_fd->fd_nfiles ||
1586 (fp = p->p_fd->fd_ofiles[args->fd]) == NULL)
1587 return (EBADF);
1588 type = fp->f_type;
1589
1590 if (type != DTYPE_SOCKET) {
1591 /* not a socket - probably a tap / vmnet device */
1592 switch (args->cmd) {
1593 case LINUX_SIOCGIFADDR:
1594 case LINUX_SIOCSIFADDR:
1595 case LINUX_SIOCGIFFLAGS:
1596 return (linux_ioctl_special(p, args));
1597 default:
1598 return (ENOIOCTL);
1599 }
1600 }
1601
1602 switch (args->cmd & 0xffff) {
1603
1604 case LINUX_FIOGETOWN:
1605 case LINUX_FIOSETOWN:
1606 case LINUX_SIOCADDMULTI:
1607 case LINUX_SIOCATMARK:
1608 case LINUX_SIOCDELMULTI:
1609 case LINUX_SIOCGIFCONF:
1610 case LINUX_SIOCGPGRP:
1611 case LINUX_SIOCSPGRP:
1612 /* these ioctls don't take an interface name */
1613 #ifdef DEBUG
1614 printf(__FUNCTION__ "(): ioctl %d\n",
1615 args->cmd & 0xffff);
1616 #endif
1617 break;
1618
1619 case LINUX_SIOCGIFFLAGS:
1620 case LINUX_SIOCGIFADDR:
1621 case LINUX_SIOCSIFADDR:
1622 case LINUX_SIOCGIFDSTADDR:
1623 case LINUX_SIOCGIFBRDADDR:
1624 case LINUX_SIOCGIFNETMASK:
1625 case LINUX_SIOCSIFNETMASK:
1626 case LINUX_SIOCGIFMTU:
1627 case LINUX_SIOCSIFMTU:
1628 case LINUX_SIOCSIFNAME:
1629 case LINUX_SIOCGIFHWADDR:
1630 case LINUX_SIOCSIFHWADDR:
1631 case LINUX_SIOCDEVPRIVATE:
1632 case LINUX_SIOCDEVPRIVATE+1:
1633 /* copy in the interface name and translate it. */
1634 error = copyin((char *)args->arg, lifname, LINUX_IFNAMSIZ);
1635 if (error != 0)
1636 return (error);
1637 #ifdef DEBUG
1638 printf(__FUNCTION__ "(): ioctl %d on %.*s\n",
1639 args->cmd & 0xffff, LINUX_IFNAMSIZ, lifname);
1640 #endif
1641 ifp = ifname_linux_to_bsd(lifname, ifname);
1642 if (ifp == NULL)
1643 return (EINVAL);
1644 /*
1645 * We need to copy it back out in case we pass the
1646 * request on to our native ioctl(), which will expect
1647 * the ifreq to be in user space and have the correct
1648 * interface name.
1649 */
1650 error = copyout(ifname, (char *)args->arg, IFNAMSIZ);
1651 if (error != 0)
1652 return (error);
1653 #ifdef DEBUG
1654 printf(__FUNCTION__ "(): %s translated to %s\n",
1655 lifname, ifname);
1656 #endif
1657 break;
1658
1659 default:
1660 return (ENOIOCTL);
1661 }
1662
1663 switch (args->cmd & 0xffff) {
1664
1665 case LINUX_FIOSETOWN:
1666 args->cmd = FIOSETOWN;
1667 error = ioctl(p, (struct ioctl_args *)args);
1668 break;
1669
1670 case LINUX_SIOCSPGRP:
1671 args->cmd = SIOCSPGRP;
1672 error = ioctl(p, (struct ioctl_args *)args);
1673 break;
1674
1675 case LINUX_FIOGETOWN:
1676 args->cmd = FIOGETOWN;
1677 error = ioctl(p, (struct ioctl_args *)args);
1678 break;
1679
1680 case LINUX_SIOCGPGRP:
1681 args->cmd = SIOCGPGRP;
1682 error = ioctl(p, (struct ioctl_args *)args);
1683 break;
1684
1685 case LINUX_SIOCATMARK:
1686 args->cmd = SIOCATMARK;
1687 error = ioctl(p, (struct ioctl_args *)args);
1688 break;
1689
1690 /* LINUX_SIOCGSTAMP */
1691
1692 case LINUX_SIOCGIFCONF:
1693 error = linux_ifconf(p, (struct ifconf *)args->arg);
1694 break;
1695
1696 case LINUX_SIOCGIFFLAGS:
1697 args->cmd = SIOCGIFFLAGS;
1698 error = linux_gifflags(p, ifp, (struct l_ifreq *)args->arg);
1699 break;
1700
1701 case LINUX_SIOCGIFADDR:
1702 args->cmd = OSIOCGIFADDR;
1703 error = ioctl(p, (struct ioctl_args *)args);
1704 break;
1705
1706 case LINUX_SIOCSIFADDR:
1707 /* XXX probably doesn't work, included for completeness */
1708 args->cmd = SIOCSIFADDR;
1709 error = ioctl(p, (struct ioctl_args *)args);
1710 break;
1711
1712 case LINUX_SIOCGIFDSTADDR:
1713 args->cmd = OSIOCGIFDSTADDR;
1714 error = ioctl(p, (struct ioctl_args *)args);
1715 break;
1716
1717 case LINUX_SIOCGIFBRDADDR:
1718 args->cmd = OSIOCGIFBRDADDR;
1719 error = ioctl(p, (struct ioctl_args *)args);
1720 break;
1721
1722 case LINUX_SIOCGIFNETMASK:
1723 args->cmd = OSIOCGIFNETMASK;
1724 error = ioctl(p, (struct ioctl_args *)args);
1725 break;
1726
1727 case LINUX_SIOCSIFNETMASK:
1728 error = ENOIOCTL;
1729 break;
1730
1731 case LINUX_SIOCGIFMTU:
1732 args->cmd = SIOCGIFMTU;
1733 error = ioctl(p, (struct ioctl_args *)args);
1734 break;
1735
1736 case LINUX_SIOCSIFMTU:
1737 args->cmd = SIOCSIFMTU;
1738 error = ioctl(p, (struct ioctl_args *)args);
1739 break;
1740
1741 case LINUX_SIOCSIFNAME:
1742 error = ENOIOCTL;
1743 break;
1744
1745 case LINUX_SIOCGIFHWADDR:
1746 error = linux_gifhwaddr(ifp, (struct l_ifreq *)args->arg);
1747 break;
1748
1749 case LINUX_SIOCSIFHWADDR:
1750 error = ENOIOCTL;
1751 break;
1752
1753 case LINUX_SIOCADDMULTI:
1754 args->cmd = SIOCADDMULTI;
1755 error = ioctl(p, (struct ioctl_args *)args);
1756 break;
1757
1758 case LINUX_SIOCDELMULTI:
1759 args->cmd = SIOCDELMULTI;
1760 error = ioctl(p, (struct ioctl_args *)args);
1761 break;
1762
1763 /*
1764 * XXX This is slightly bogus, but these ioctls are currently
1765 * XXX only used by the aironet (if_an) network driver.
1766 */
1767 case LINUX_SIOCDEVPRIVATE:
1768 args->cmd = SIOCGPRIVATE_0;
1769 error = ioctl(p, (struct ioctl_args *)args);
1770 break;
1771
1772 case LINUX_SIOCDEVPRIVATE+1:
1773 args->cmd = SIOCGPRIVATE_1;
1774 error = ioctl(p, (struct ioctl_args *)args);
1775 break;
1776 }
1777
1778 if (ifp != NULL)
1779 /* restore the original interface name */
1780 copyout(lifname, (char *)args->arg, LINUX_IFNAMSIZ);
1781
1782 #ifdef DEBUG
1783 printf(__FUNCTION__ "(): returning %d\n", error);
1784 #endif
1785 return (error);
1786 }
1787
1788 /*
1789 * Device private ioctl handler
1790 */
1791 static int
1792 linux_ioctl_private(struct proc *p, struct linux_ioctl_args *args)
1793 {
1794 struct filedesc *fdp;
1795 struct file *fp;
1796 int type;
1797
1798 fdp = p->p_fd;
1799 if (args->fd >= fdp->fd_nfiles ||
1800 (fp = fdp->fd_ofiles[args->fd]) == NULL) {
1801 return (EBADF);
1802 } else {
1803 type = fp->f_type;
1804 }
1805 if (type == DTYPE_SOCKET)
1806 return (linux_ioctl_socket(p, args));
1807 return (ENOIOCTL);
1808 }
1809
1810 /*
1811 * DRM ioctl handler (sys/dev/drm)
1812 */
1813 static int
1814 linux_ioctl_drm(struct proc *p, struct linux_ioctl_args *args)
1815 {
1816 args->cmd = SETDIR(args->cmd);
1817 return ioctl(p, (struct ioctl_args *)args);
1818 }
1819
1820 /*
1821 * Special ioctl handler
1822 */
1823 static int
1824 linux_ioctl_special(struct proc *p, struct linux_ioctl_args *args)
1825 {
1826 int error;
1827
1828 switch (args->cmd) {
1829 case LINUX_SIOCGIFADDR:
1830 args->cmd = SIOCGIFADDR;
1831 error = ioctl(p, (struct ioctl_args *)args);
1832 break;
1833 case LINUX_SIOCSIFADDR:
1834 args->cmd = SIOCSIFADDR;
1835 error = ioctl(p, (struct ioctl_args *)args);
1836 break;
1837 case LINUX_SIOCGIFFLAGS:
1838 args->cmd = SIOCGIFFLAGS;
1839 error = ioctl(p, (struct ioctl_args *)args);
1840 break;
1841 default:
1842 error = ENOIOCTL;
1843 }
1844
1845 return (error);
1846 }
1847
1848 /*
1849 * main ioctl syscall function
1850 */
1851
1852 int
1853 linux_ioctl(struct proc *p, struct linux_ioctl_args *args)
1854 {
1855 struct filedesc *fdp;
1856 struct file *fp;
1857 struct handler_element *he;
1858 int error, cmd;
1859
1860 #ifdef DEBUG
1861 if (ldebug(ioctl))
1862 printf(ARGS(ioctl, "%d, %04lx, *"), args->fd, args->cmd);
1863 #endif
1864
1865 fdp = p->p_fd;
1866 if ((unsigned)args->fd >= fdp->fd_nfiles)
1867 return (EBADF);
1868 fp = fdp->fd_ofiles[args->fd];
1869 if (fp == NULL || (fp->f_flag & (FREAD|FWRITE)) == 0)
1870 return (EBADF);
1871
1872 /* Iterate over the ioctl handlers */
1873 cmd = args->cmd & 0xffff;
1874 TAILQ_FOREACH(he, &handlers, list) {
1875 if (cmd >= he->low && cmd <= he->high) {
1876 error = (*he->func)(p, args);
1877 if (error != ENOIOCTL)
1878 return (error);
1879 }
1880 }
1881
1882 printf("linux: 'ioctl' fd=%d, cmd=0x%x ('%c',%d) not implemented\n",
1883 args->fd, (int)(args->cmd & 0xffff),
1884 (int)(args->cmd & 0xff00) >> 8, (int)(args->cmd & 0xff));
1885
1886 return (EINVAL);
1887 }
1888
1889 int
1890 linux_ioctl_register_handlers(struct linker_set *s)
1891 {
1892 int error, i;
1893
1894 if (s == NULL)
1895 return (EINVAL);
1896
1897 for (i = 0; i < s->ls_length; i++) {
1898 error = linux_ioctl_register_handler(s->ls_items[i]);
1899 if (error)
1900 return (error);
1901 }
1902
1903 return (0);
1904 }
1905
1906 int
1907 linux_ioctl_unregister_handlers(struct linker_set *s)
1908 {
1909 int error, i;
1910
1911 if (s == NULL)
1912 return (EINVAL);
1913
1914 for (i = 0; i < s->ls_length; i++) {
1915 error = linux_ioctl_unregister_handler(s->ls_items[i]);
1916 if (error)
1917 return (error);
1918 }
1919
1920 return (0);
1921 }
1922
1923 int
1924 linux_ioctl_register_handler(struct linux_ioctl_handler *h)
1925 {
1926 struct handler_element *he, *cur;
1927
1928 if (h == NULL || h->func == NULL)
1929 return (EINVAL);
1930
1931 /*
1932 * Reuse the element if the handler is already on the list, otherwise
1933 * create a new element.
1934 */
1935 TAILQ_FOREACH(he, &handlers, list) {
1936 if (he->func == h->func)
1937 break;
1938 }
1939 if (he == NULL) {
1940 MALLOC(he, struct handler_element *, sizeof(*he),
1941 M_LINUX, M_WAITOK);
1942 he->func = h->func;
1943 } else
1944 TAILQ_REMOVE(&handlers, he, list);
1945
1946 /* Initialize range information. */
1947 he->low = h->low;
1948 he->high = h->high;
1949 he->span = h->high - h->low + 1;
1950
1951 /* Add the element to the list, sorted on span. */
1952 TAILQ_FOREACH(cur, &handlers, list) {
1953 if (cur->span > he->span) {
1954 TAILQ_INSERT_BEFORE(cur, he, list);
1955 return (0);
1956 }
1957 }
1958 TAILQ_INSERT_TAIL(&handlers, he, list);
1959
1960 return (0);
1961 }
1962
1963 int
1964 linux_ioctl_unregister_handler(struct linux_ioctl_handler *h)
1965 {
1966 struct handler_element *he;
1967
1968 if (h == NULL || h->func == NULL)
1969 return (EINVAL);
1970
1971 TAILQ_FOREACH(he, &handlers, list) {
1972 if (he->func == h->func) {
1973 TAILQ_REMOVE(&handlers, he, list);
1974 FREE(he, M_LINUX);
1975 return (0);
1976 }
1977 }
1978
1979 return (EINVAL);
1980 }
Cache object: 098a786f11b6b3d495582cfc00381807
|