2005-01-05 22:34:37 +00:00
|
|
|
/*-
|
2018-02-16 15:00:14 +00:00
|
|
|
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
2017-11-27 15:13:23 +00:00
|
|
|
*
|
2012-01-15 13:23:18 +00:00
|
|
|
* Copyright (c) 1994-1995 Søren Schmidt
|
1995-06-25 17:32:43 +00:00
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
2018-02-16 15:00:14 +00:00
|
|
|
* notice, this list of conditions and the following disclaimer.
|
1995-06-25 17:32:43 +00:00
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
*
|
2018-02-16 15:00:14 +00:00
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
1995-06-25 17:32:43 +00:00
|
|
|
*/
|
|
|
|
|
2008-08-25 04:55:29 +00:00
|
|
|
#include "opt_compat.h"
|
|
|
|
|
2003-06-10 21:29:12 +00:00
|
|
|
#include <sys/cdefs.h>
|
|
|
|
__FBSDID("$FreeBSD$");
|
|
|
|
|
1995-06-25 17:32:43 +00:00
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/systm.h>
|
1995-11-22 07:43:53 +00:00
|
|
|
#include <sys/sysproto.h>
|
2014-03-16 10:55:57 +00:00
|
|
|
#include <sys/capsicum.h>
|
1999-04-29 04:37:57 +00:00
|
|
|
#include <sys/cdio.h>
|
2001-11-18 18:49:07 +00:00
|
|
|
#include <sys/dvdio.h>
|
2003-04-01 12:34:47 +00:00
|
|
|
#include <sys/conf.h>
|
2003-03-28 08:58:11 +00:00
|
|
|
#include <sys/disk.h>
|
2000-10-08 21:34:00 +00:00
|
|
|
#include <sys/consio.h>
|
2001-10-15 20:52:17 +00:00
|
|
|
#include <sys/ctype.h>
|
1997-03-23 03:37:54 +00:00
|
|
|
#include <sys/fcntl.h>
|
1995-06-25 17:32:43 +00:00
|
|
|
#include <sys/file.h>
|
|
|
|
#include <sys/filedesc.h>
|
1997-03-24 11:37:53 +00:00
|
|
|
#include <sys/filio.h>
|
2009-06-17 15:01:01 +00:00
|
|
|
#include <sys/jail.h>
|
2000-10-08 21:34:00 +00:00
|
|
|
#include <sys/kbio.h>
|
2006-07-06 21:42:36 +00:00
|
|
|
#include <sys/kernel.h>
|
1999-12-04 11:10:22 +00:00
|
|
|
#include <sys/linker_set.h>
|
2006-07-06 21:42:36 +00:00
|
|
|
#include <sys/lock.h>
|
1999-12-04 11:10:22 +00:00
|
|
|
#include <sys/malloc.h>
|
2001-10-15 20:52:17 +00:00
|
|
|
#include <sys/proc.h>
|
2005-08-27 14:44:10 +00:00
|
|
|
#include <sys/sbuf.h>
|
Mega-commit for Linux emulator update.. This has been stress tested under
netscape-2.0 for Linux running all the Java stuff. The scrollbars are now
working, at least on my machine. (whew! :-)
I'm uncomfortable with the size of this commit, but it's too
inter-dependant to easily seperate out.
The main changes:
COMPAT_LINUX is *GONE*. Most of the code has been moved out of the i386
machine dependent section into the linux emulator itself. The int 0x80
syscall code was almost identical to the lcall 7,0 code and a minor tweak
allows them to both be used with the same C code. All kernels can now
just modload the lkm and it'll DTRT without having to rebuild the kernel
first. Like IBCS2, you can statically compile it in with "options LINUX".
A pile of new syscalls implemented, including getdents(), llseek(),
readv(), writev(), msync(), personality(). The Linux-ELF libraries want
to use some of these.
linux_select() now obeys Linux semantics, ie: returns the time remaining
of the timeout value rather than leaving it the original value.
Quite a few bugs removed, including incorrect arguments being used in
syscalls.. eg: mixups between passing the sigset as an int, vs passing
it as a pointer and doing a copyin(), missing return values, unhandled
cases, SIOC* ioctls, etc.
The build for the code has changed. i386/conf/files now knows how
to build linux_genassym and generate linux_assym.h on the fly.
Supporting changes elsewhere in the kernel:
The user-mode signal trampoline has moved from the U area to immediately
below the top of the stack (below PS_STRINGS). This allows the different
binary emulations to have their own signal trampoline code (which gets rid
of the hardwired syscall 103 (sigreturn on BSD, syslog on Linux)) and so
that the emulator can provide the exact "struct sigcontext *" argument to
the program's signal handlers.
The sigstack's "ss_flags" now uses SS_DISABLE and SS_ONSTACK flags, which
have the same values as the re-used SA_DISABLE and SA_ONSTACK which are
intended for sigaction only. This enables the support of a SA_RESETHAND
flag to sigaction to implement the gross SYSV and Linux SA_ONESHOT signal
semantics where the signal handler is reset when it's triggered.
makesyscalls.sh no longer appends the struct sysentvec on the end of the
generated init_sysent.c code. It's a lot saner to have it in a seperate
file rather than trying to update the structure inside the awk script. :-)
At exec time, the dozen bytes or so of signal trampoline code are copied
to the top of the user's stack, rather than obtaining the trampoline code
the old way by getting a clone of the parent's user area. This allows
Linux and native binaries to freely exec each other without getting
trampolines mixed up.
1996-03-02 19:38:20 +00:00
|
|
|
#include <sys/socket.h>
|
2001-10-15 20:52:17 +00:00
|
|
|
#include <sys/sockio.h>
|
|
|
|
#include <sys/soundcard.h>
|
2004-06-14 07:26:23 +00:00
|
|
|
#include <sys/stdint.h>
|
2006-07-06 21:42:36 +00:00
|
|
|
#include <sys/sx.h>
|
2011-05-04 09:52:34 +00:00
|
|
|
#include <sys/sysctl.h>
|
2001-10-15 20:52:17 +00:00
|
|
|
#include <sys/tty.h>
|
|
|
|
#include <sys/uio.h>
|
2011-05-04 09:05:39 +00:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/mman.h>
|
|
|
|
#include <sys/resourcevar.h>
|
Commit step 1 of the vimage project, (network stack)
virtualization work done by Marko Zec (zec@).
This is the first in a series of commits over the course
of the next few weeks.
Mark all uses of global variables to be virtualized
with a V_ prefix.
Use macros to map them back to their global names for
now, so this is a NOP change only.
We hope to have caught at least 85-90% of what is needed
so we do not invalidate a lot of outstanding patches again.
Obtained from: //depot/projects/vimage-commit2/...
Reviewed by: brooks, des, ed, mav, julian,
jamie, kris, rwatson, zec, ...
(various people I forgot, different versions)
md5 (with a bit of help)
Sponsored by: NLnet Foundation, The FreeBSD Foundation
X-MFC after: never
V_Commit_Message_Reviewed_By: more people than the patch
2008-08-17 23:27:27 +00:00
|
|
|
|
Mega-commit for Linux emulator update.. This has been stress tested under
netscape-2.0 for Linux running all the Java stuff. The scrollbars are now
working, at least on my machine. (whew! :-)
I'm uncomfortable with the size of this commit, but it's too
inter-dependant to easily seperate out.
The main changes:
COMPAT_LINUX is *GONE*. Most of the code has been moved out of the i386
machine dependent section into the linux emulator itself. The int 0x80
syscall code was almost identical to the lcall 7,0 code and a minor tweak
allows them to both be used with the same C code. All kernels can now
just modload the lkm and it'll DTRT without having to rebuild the kernel
first. Like IBCS2, you can statically compile it in with "options LINUX".
A pile of new syscalls implemented, including getdents(), llseek(),
readv(), writev(), msync(), personality(). The Linux-ELF libraries want
to use some of these.
linux_select() now obeys Linux semantics, ie: returns the time remaining
of the timeout value rather than leaving it the original value.
Quite a few bugs removed, including incorrect arguments being used in
syscalls.. eg: mixups between passing the sigset as an int, vs passing
it as a pointer and doing a copyin(), missing return values, unhandled
cases, SIOC* ioctls, etc.
The build for the code has changed. i386/conf/files now knows how
to build linux_genassym and generate linux_assym.h on the fly.
Supporting changes elsewhere in the kernel:
The user-mode signal trampoline has moved from the U area to immediately
below the top of the stack (below PS_STRINGS). This allows the different
binary emulations to have their own signal trampoline code (which gets rid
of the hardwired syscall 103 (sigreturn on BSD, syslog on Linux)) and so
that the emulator can provide the exact "struct sigcontext *" argument to
the program's signal handlers.
The sigstack's "ss_flags" now uses SS_DISABLE and SS_ONSTACK flags, which
have the same values as the re-used SA_DISABLE and SA_ONSTACK which are
intended for sigaction only. This enables the support of a SA_RESETHAND
flag to sigaction to implement the gross SYSV and Linux SA_ONESHOT signal
semantics where the signal handler is reset when it's triggered.
makesyscalls.sh no longer appends the struct sysentvec on the end of the
generated init_sysent.c code. It's a lot saner to have it in a seperate
file rather than trying to update the structure inside the awk script. :-)
At exec time, the dozen bytes or so of signal trampoline code are copied
to the top of the user's stack, rather than obtaining the trampoline code
the old way by getting a clone of the parent's user area. This allows
Linux and native binaries to freely exec each other without getting
trampolines mixed up.
1996-03-02 19:38:20 +00:00
|
|
|
#include <net/if.h>
|
2013-10-26 17:58:36 +00:00
|
|
|
#include <net/if_var.h>
|
1997-06-02 06:31:49 +00:00
|
|
|
#include <net/if_dl.h>
|
|
|
|
#include <net/if_types.h>
|
1995-11-22 07:43:53 +00:00
|
|
|
|
2017-04-23 07:43:50 +00:00
|
|
|
#include <dev/evdev/input.h>
|
2010-05-24 07:04:00 +00:00
|
|
|
#include <dev/usb/usb_ioctl.h>
|
|
|
|
|
2005-01-14 04:44:56 +00:00
|
|
|
#ifdef COMPAT_LINUX32
|
2004-08-16 07:28:16 +00:00
|
|
|
#include <machine/../linux32/linux.h>
|
|
|
|
#include <machine/../linux32/linux32_proto.h>
|
2005-01-14 04:44:56 +00:00
|
|
|
#else
|
|
|
|
#include <machine/../linux/linux.h>
|
|
|
|
#include <machine/../linux/linux_proto.h>
|
2004-08-16 07:28:16 +00:00
|
|
|
#endif
|
2000-11-01 19:48:35 +00:00
|
|
|
|
2000-08-22 01:32:14 +00:00
|
|
|
#include <compat/linux/linux_ioctl.h>
|
|
|
|
#include <compat/linux/linux_mib.h>
|
2009-05-07 09:39:20 +00:00
|
|
|
#include <compat/linux/linux_socket.h>
|
2017-04-23 07:43:50 +00:00
|
|
|
#include <compat/linux/linux_timer.h>
|
2000-08-22 01:32:14 +00:00
|
|
|
#include <compat/linux/linux_util.h>
|
1995-06-25 17:32:43 +00:00
|
|
|
|
2013-07-06 19:59:06 +00:00
|
|
|
#include <contrib/v4l/videodev.h>
|
2009-12-04 21:06:54 +00:00
|
|
|
#include <compat/linux/linux_videodev_compat.h>
|
|
|
|
|
2013-07-06 19:59:06 +00:00
|
|
|
#include <contrib/v4l/videodev2.h>
|
2011-05-04 09:05:39 +00:00
|
|
|
#include <compat/linux/linux_videodev2_compat.h>
|
|
|
|
|
2014-06-02 19:53:53 +00:00
|
|
|
#include <cam/scsi/scsi_sg.h>
|
|
|
|
|
2005-03-24 19:26:50 +00:00
|
|
|
CTASSERT(LINUX_IFNAMSIZ == IFNAMSIZ);
|
2005-03-24 17:51:15 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
static linux_ioctl_function_t linux_ioctl_cdrom;
|
2002-10-11 11:43:09 +00:00
|
|
|
static linux_ioctl_function_t linux_ioctl_vfat;
|
1999-12-04 11:10:22 +00:00
|
|
|
static linux_ioctl_function_t linux_ioctl_console;
|
2004-06-14 07:26:23 +00:00
|
|
|
static linux_ioctl_function_t linux_ioctl_hdio;
|
2000-03-13 15:27:19 +00:00
|
|
|
static linux_ioctl_function_t linux_ioctl_disk;
|
1999-12-04 11:10:22 +00:00
|
|
|
static linux_ioctl_function_t linux_ioctl_socket;
|
|
|
|
static linux_ioctl_function_t linux_ioctl_sound;
|
|
|
|
static linux_ioctl_function_t linux_ioctl_termio;
|
2001-10-19 01:38:10 +00:00
|
|
|
static linux_ioctl_function_t linux_ioctl_private;
|
2003-04-24 23:36:35 +00:00
|
|
|
static linux_ioctl_function_t linux_ioctl_drm;
|
2007-04-07 19:40:58 +00:00
|
|
|
static linux_ioctl_function_t linux_ioctl_sg;
|
2009-12-04 21:06:54 +00:00
|
|
|
static linux_ioctl_function_t linux_ioctl_v4l;
|
2011-05-04 09:05:39 +00:00
|
|
|
static linux_ioctl_function_t linux_ioctl_v4l2;
|
2001-11-19 15:43:50 +00:00
|
|
|
static linux_ioctl_function_t linux_ioctl_special;
|
2010-01-18 22:46:06 +00:00
|
|
|
static linux_ioctl_function_t linux_ioctl_fbsd_usb;
|
2017-04-23 07:43:50 +00:00
|
|
|
static linux_ioctl_function_t linux_ioctl_evdev;
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
static struct linux_ioctl_handler cdrom_handler =
|
|
|
|
{ linux_ioctl_cdrom, LINUX_IOCTL_CDROM_MIN, LINUX_IOCTL_CDROM_MAX };
|
2002-10-11 11:43:09 +00:00
|
|
|
static struct linux_ioctl_handler vfat_handler =
|
|
|
|
{ linux_ioctl_vfat, LINUX_IOCTL_VFAT_MIN, LINUX_IOCTL_VFAT_MAX };
|
1999-12-04 11:10:22 +00:00
|
|
|
static struct linux_ioctl_handler console_handler =
|
|
|
|
{ linux_ioctl_console, LINUX_IOCTL_CONSOLE_MIN, LINUX_IOCTL_CONSOLE_MAX };
|
2004-06-14 07:26:23 +00:00
|
|
|
static struct linux_ioctl_handler hdio_handler =
|
|
|
|
{ linux_ioctl_hdio, LINUX_IOCTL_HDIO_MIN, LINUX_IOCTL_HDIO_MAX };
|
2000-03-13 15:27:19 +00:00
|
|
|
static struct linux_ioctl_handler disk_handler =
|
|
|
|
{ linux_ioctl_disk, LINUX_IOCTL_DISK_MIN, LINUX_IOCTL_DISK_MAX };
|
1999-12-04 11:10:22 +00:00
|
|
|
static struct linux_ioctl_handler socket_handler =
|
|
|
|
{ linux_ioctl_socket, LINUX_IOCTL_SOCKET_MIN, LINUX_IOCTL_SOCKET_MAX };
|
|
|
|
static struct linux_ioctl_handler sound_handler =
|
|
|
|
{ linux_ioctl_sound, LINUX_IOCTL_SOUND_MIN, LINUX_IOCTL_SOUND_MAX };
|
|
|
|
static struct linux_ioctl_handler termio_handler =
|
|
|
|
{ linux_ioctl_termio, LINUX_IOCTL_TERMIO_MIN, LINUX_IOCTL_TERMIO_MAX };
|
2001-10-19 01:38:10 +00:00
|
|
|
static struct linux_ioctl_handler private_handler =
|
|
|
|
{ linux_ioctl_private, LINUX_IOCTL_PRIVATE_MIN, LINUX_IOCTL_PRIVATE_MAX };
|
2003-04-24 23:36:35 +00:00
|
|
|
static struct linux_ioctl_handler drm_handler =
|
|
|
|
{ linux_ioctl_drm, LINUX_IOCTL_DRM_MIN, LINUX_IOCTL_DRM_MAX };
|
2007-04-07 19:40:58 +00:00
|
|
|
static struct linux_ioctl_handler sg_handler =
|
|
|
|
{ linux_ioctl_sg, LINUX_IOCTL_SG_MIN, LINUX_IOCTL_SG_MAX };
|
2009-12-04 21:06:54 +00:00
|
|
|
static struct linux_ioctl_handler video_handler =
|
|
|
|
{ linux_ioctl_v4l, LINUX_IOCTL_VIDEO_MIN, LINUX_IOCTL_VIDEO_MAX };
|
2011-05-04 09:05:39 +00:00
|
|
|
static struct linux_ioctl_handler video2_handler =
|
|
|
|
{ linux_ioctl_v4l2, LINUX_IOCTL_VIDEO2_MIN, LINUX_IOCTL_VIDEO2_MAX };
|
2010-01-18 22:46:06 +00:00
|
|
|
static struct linux_ioctl_handler fbsd_usb =
|
2010-05-24 07:04:00 +00:00
|
|
|
{ linux_ioctl_fbsd_usb, FBSD_LUSB_MIN, FBSD_LUSB_MAX };
|
2017-04-23 07:43:50 +00:00
|
|
|
static struct linux_ioctl_handler evdev_handler =
|
|
|
|
{ linux_ioctl_evdev, LINUX_IOCTL_EVDEV_MIN, LINUX_IOCTL_EVDEV_MAX };
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
DATA_SET(linux_ioctl_handler_set, cdrom_handler);
|
2002-10-11 11:43:09 +00:00
|
|
|
DATA_SET(linux_ioctl_handler_set, vfat_handler);
|
1999-12-04 11:10:22 +00:00
|
|
|
DATA_SET(linux_ioctl_handler_set, console_handler);
|
2004-06-14 07:26:23 +00:00
|
|
|
DATA_SET(linux_ioctl_handler_set, hdio_handler);
|
2000-03-13 15:27:19 +00:00
|
|
|
DATA_SET(linux_ioctl_handler_set, disk_handler);
|
1999-12-04 11:10:22 +00:00
|
|
|
DATA_SET(linux_ioctl_handler_set, socket_handler);
|
|
|
|
DATA_SET(linux_ioctl_handler_set, sound_handler);
|
|
|
|
DATA_SET(linux_ioctl_handler_set, termio_handler);
|
2001-10-19 01:38:10 +00:00
|
|
|
DATA_SET(linux_ioctl_handler_set, private_handler);
|
2003-04-24 23:36:35 +00:00
|
|
|
DATA_SET(linux_ioctl_handler_set, drm_handler);
|
2007-04-07 19:40:58 +00:00
|
|
|
DATA_SET(linux_ioctl_handler_set, sg_handler);
|
2009-12-04 21:06:54 +00:00
|
|
|
DATA_SET(linux_ioctl_handler_set, video_handler);
|
2011-05-04 09:05:39 +00:00
|
|
|
DATA_SET(linux_ioctl_handler_set, video2_handler);
|
2010-01-18 22:46:06 +00:00
|
|
|
DATA_SET(linux_ioctl_handler_set, fbsd_usb);
|
2017-04-23 07:43:50 +00:00
|
|
|
DATA_SET(linux_ioctl_handler_set, evdev_handler);
|
1999-12-04 11:10:22 +00:00
|
|
|
|
2003-03-02 15:56:49 +00:00
|
|
|
struct handler_element
|
1999-12-04 11:10:22 +00:00
|
|
|
{
|
2000-05-26 02:09:24 +00:00
|
|
|
TAILQ_ENTRY(handler_element) list;
|
2001-09-12 08:38:13 +00:00
|
|
|
int (*func)(struct thread *, struct linux_ioctl_args *);
|
1999-12-04 11:10:22 +00:00
|
|
|
int low, high, span;
|
|
|
|
};
|
|
|
|
|
2000-05-26 02:09:24 +00:00
|
|
|
static TAILQ_HEAD(, handler_element) handlers =
|
Whitespace change to be able to provide the correct commit log for r202364:
---snip---
Add video clipping support but with the caveats below.
Background info:
Video clipping allows the user to provide either a series of clip rectangles
or a clip bitmap to the driver and have the driver mask the video according
to the clipping specs provided.
Adding support for clipping to the FreeBSD Linux emulator is problematic
because it seems that this feature is not supported by many drivers and
therefore it is ignored by many applications. Unfortunately, when not
using it, rather than passing in a null clipping list, some apps leave the
clipping fields uninitialized, casuing random values to be passed in. In
the case where the driver does not use the clipping info, this is not a
problem (although it is bad form). But the Linux emulator does not know
which drivers will use this and which won't, so the Linux emulator must
try to handle this clip list, and deal gracefully with cases where the
values seem to be uninitialized.
Video clipping info is passed in using the VIDIOCSWIN ioctl in two fields
in the video_window structure: the integer clipcount and the pointer clips.
How the linuxulator handles this from this commit on:
* if (clipcount == VIDEO_CLIP_BITMAP)
The clips variable is a void * pointer to a 128*625 byte
(1024*625 bit) memory area containing a bitmap of the clipping area.
The pointer in the video_window structure is copied, but no
video_clip structures are copied.
* if (clipcount > 0 && clipcount <= 16384)
The clips variable is pointer to a list of video_clip structures. Up
to clipcount structures are copied and passed to the driver.
The upper limit of 16384 was imposed here so that user code that does
not properly initialize clipcount falls through below and no attempt
is made to copy an uninitialized list. This value was found by
examining Linux drivers that support the clip list.
* else
The clipcount is either negative (but not VIDEO_CLIP_BITMAP), zero or
positive (> 16384).
All these cases are treated as invalid data. Both the clipcount field
and clips pointer are forced to zero/NULL and passed to the driver.
It should be noted that, at the time of developing this V4L emulator code,
the pwc(4) V4L driver does not support clipping.
Submitted by: J.R. Oldroyd <fbsd@opal.com>
MFC after: 1 month
---snip---
2010-01-15 15:38:31 +00:00
|
|
|
TAILQ_HEAD_INITIALIZER(handlers);
|
2006-07-06 21:42:36 +00:00
|
|
|
static struct sx linux_ioctl_sx;
|
2018-02-22 02:24:17 +00:00
|
|
|
SX_SYSINIT(linux_ioctl, &linux_ioctl_sx, "Linux ioctl handlers");
|
1999-12-04 11:10:22 +00:00
|
|
|
|
2004-06-14 07:26:23 +00:00
|
|
|
/*
|
|
|
|
* hdio related ioctls for VMWare support
|
|
|
|
*/
|
|
|
|
|
|
|
|
struct linux_hd_geometry {
|
|
|
|
u_int8_t heads;
|
|
|
|
u_int8_t sectors;
|
|
|
|
u_int16_t cylinders;
|
|
|
|
u_int32_t start;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct linux_hd_big_geometry {
|
|
|
|
u_int8_t heads;
|
|
|
|
u_int8_t sectors;
|
|
|
|
u_int32_t cylinders;
|
|
|
|
u_int32_t start;
|
|
|
|
};
|
|
|
|
|
|
|
|
static int
|
|
|
|
linux_ioctl_hdio(struct thread *td, struct linux_ioctl_args *args)
|
|
|
|
{
|
Change the cap_rights_t type from uint64_t to a structure that we can extend
in the future in a backward compatible (API and ABI) way.
The cap_rights_t represents capability rights. We used to use one bit to
represent one right, but we are running out of spare bits. Currently the new
structure provides place for 114 rights (so 50 more than the previous
cap_rights_t), but it is possible to grow the structure to hold at least 285
rights, although we can make it even larger if 285 rights won't be enough.
The structure definition looks like this:
struct cap_rights {
uint64_t cr_rights[CAP_RIGHTS_VERSION + 2];
};
The initial CAP_RIGHTS_VERSION is 0.
The top two bits in the first element of the cr_rights[] array contain total
number of elements in the array - 2. This means if those two bits are equal to
0, we have 2 array elements.
The top two bits in all remaining array elements should be 0.
The next five bits in all array elements contain array index. Only one bit is
used and bit position in this five-bits range defines array index. This means
there can be at most five array elements in the future.
To define new right the CAPRIGHT() macro must be used. The macro takes two
arguments - an array index and a bit to set, eg.
#define CAP_PDKILL CAPRIGHT(1, 0x0000000000000800ULL)
We still support aliases that combine few rights, but the rights have to belong
to the same array element, eg:
#define CAP_LOOKUP CAPRIGHT(0, 0x0000000000000400ULL)
#define CAP_FCHMOD CAPRIGHT(0, 0x0000000000002000ULL)
#define CAP_FCHMODAT (CAP_FCHMOD | CAP_LOOKUP)
There is new API to manage the new cap_rights_t structure:
cap_rights_t *cap_rights_init(cap_rights_t *rights, ...);
void cap_rights_set(cap_rights_t *rights, ...);
void cap_rights_clear(cap_rights_t *rights, ...);
bool cap_rights_is_set(const cap_rights_t *rights, ...);
bool cap_rights_is_valid(const cap_rights_t *rights);
void cap_rights_merge(cap_rights_t *dst, const cap_rights_t *src);
void cap_rights_remove(cap_rights_t *dst, const cap_rights_t *src);
bool cap_rights_contains(const cap_rights_t *big, const cap_rights_t *little);
Capability rights to the cap_rights_init(), cap_rights_set(),
cap_rights_clear() and cap_rights_is_set() functions are provided by
separating them with commas, eg:
cap_rights_t rights;
cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_FSTAT);
There is no need to terminate the list of rights, as those functions are
actually macros that take care of the termination, eg:
#define cap_rights_set(rights, ...) \
__cap_rights_set((rights), __VA_ARGS__, 0ULL)
void __cap_rights_set(cap_rights_t *rights, ...);
Thanks to using one bit as an array index we can assert in those functions that
there are no two rights belonging to different array elements provided
together. For example this is illegal and will be detected, because CAP_LOOKUP
belongs to element 0 and CAP_PDKILL to element 1:
cap_rights_init(&rights, CAP_LOOKUP | CAP_PDKILL);
Providing several rights that belongs to the same array's element this way is
correct, but is not advised. It should only be used for aliases definition.
This commit also breaks compatibility with some existing Capsicum system calls,
but I see no other way to do that. This should be fine as Capsicum is still
experimental and this change is not going to 9.x.
Sponsored by: The FreeBSD Foundation
2013-09-05 00:09:56 +00:00
|
|
|
cap_rights_t rights;
|
2004-06-14 07:26:23 +00:00
|
|
|
struct file *fp;
|
|
|
|
int error;
|
|
|
|
u_int sectorsize, fwcylinders, fwheads, fwsectors;
|
|
|
|
off_t mediasize, bytespercyl;
|
|
|
|
|
Change the cap_rights_t type from uint64_t to a structure that we can extend
in the future in a backward compatible (API and ABI) way.
The cap_rights_t represents capability rights. We used to use one bit to
represent one right, but we are running out of spare bits. Currently the new
structure provides place for 114 rights (so 50 more than the previous
cap_rights_t), but it is possible to grow the structure to hold at least 285
rights, although we can make it even larger if 285 rights won't be enough.
The structure definition looks like this:
struct cap_rights {
uint64_t cr_rights[CAP_RIGHTS_VERSION + 2];
};
The initial CAP_RIGHTS_VERSION is 0.
The top two bits in the first element of the cr_rights[] array contain total
number of elements in the array - 2. This means if those two bits are equal to
0, we have 2 array elements.
The top two bits in all remaining array elements should be 0.
The next five bits in all array elements contain array index. Only one bit is
used and bit position in this five-bits range defines array index. This means
there can be at most five array elements in the future.
To define new right the CAPRIGHT() macro must be used. The macro takes two
arguments - an array index and a bit to set, eg.
#define CAP_PDKILL CAPRIGHT(1, 0x0000000000000800ULL)
We still support aliases that combine few rights, but the rights have to belong
to the same array element, eg:
#define CAP_LOOKUP CAPRIGHT(0, 0x0000000000000400ULL)
#define CAP_FCHMOD CAPRIGHT(0, 0x0000000000002000ULL)
#define CAP_FCHMODAT (CAP_FCHMOD | CAP_LOOKUP)
There is new API to manage the new cap_rights_t structure:
cap_rights_t *cap_rights_init(cap_rights_t *rights, ...);
void cap_rights_set(cap_rights_t *rights, ...);
void cap_rights_clear(cap_rights_t *rights, ...);
bool cap_rights_is_set(const cap_rights_t *rights, ...);
bool cap_rights_is_valid(const cap_rights_t *rights);
void cap_rights_merge(cap_rights_t *dst, const cap_rights_t *src);
void cap_rights_remove(cap_rights_t *dst, const cap_rights_t *src);
bool cap_rights_contains(const cap_rights_t *big, const cap_rights_t *little);
Capability rights to the cap_rights_init(), cap_rights_set(),
cap_rights_clear() and cap_rights_is_set() functions are provided by
separating them with commas, eg:
cap_rights_t rights;
cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_FSTAT);
There is no need to terminate the list of rights, as those functions are
actually macros that take care of the termination, eg:
#define cap_rights_set(rights, ...) \
__cap_rights_set((rights), __VA_ARGS__, 0ULL)
void __cap_rights_set(cap_rights_t *rights, ...);
Thanks to using one bit as an array index we can assert in those functions that
there are no two rights belonging to different array elements provided
together. For example this is illegal and will be detected, because CAP_LOOKUP
belongs to element 0 and CAP_PDKILL to element 1:
cap_rights_init(&rights, CAP_LOOKUP | CAP_PDKILL);
Providing several rights that belongs to the same array's element this way is
correct, but is not advised. It should only be used for aliases definition.
This commit also breaks compatibility with some existing Capsicum system calls,
but I see no other way to do that. This should be fine as Capsicum is still
experimental and this change is not going to 9.x.
Sponsored by: The FreeBSD Foundation
2013-09-05 00:09:56 +00:00
|
|
|
error = fget(td, args->fd, cap_rights_init(&rights, CAP_IOCTL), &fp);
|
|
|
|
if (error != 0)
|
2004-06-14 07:26:23 +00:00
|
|
|
return (error);
|
|
|
|
switch (args->cmd & 0xffff) {
|
|
|
|
case LINUX_HDIO_GET_GEO:
|
|
|
|
case LINUX_HDIO_GET_GEO_BIG:
|
|
|
|
error = fo_ioctl(fp, DIOCGMEDIASIZE,
|
|
|
|
(caddr_t)&mediasize, td->td_ucred, td);
|
|
|
|
if (!error)
|
|
|
|
error = fo_ioctl(fp, DIOCGSECTORSIZE,
|
|
|
|
(caddr_t)§orsize, td->td_ucred, td);
|
|
|
|
if (!error)
|
|
|
|
error = fo_ioctl(fp, DIOCGFWHEADS,
|
|
|
|
(caddr_t)&fwheads, td->td_ucred, td);
|
|
|
|
if (!error)
|
|
|
|
error = fo_ioctl(fp, DIOCGFWSECTORS,
|
|
|
|
(caddr_t)&fwsectors, td->td_ucred, td);
|
|
|
|
/*
|
|
|
|
* XXX: DIOCGFIRSTOFFSET is not yet implemented, so
|
|
|
|
* so pretend that GEOM always says 0. This is NOT VALID
|
|
|
|
* for slices or partitions, only the per-disk raw devices.
|
|
|
|
*/
|
|
|
|
|
|
|
|
fdrop(fp, td);
|
|
|
|
if (error)
|
|
|
|
return (error);
|
|
|
|
/*
|
|
|
|
* 1. Calculate the number of bytes in a cylinder,
|
|
|
|
* given the firmware's notion of heads and sectors
|
|
|
|
* per cylinder.
|
|
|
|
* 2. Calculate the number of cylinders, given the total
|
|
|
|
* size of the media.
|
|
|
|
* All internal calculations should have 64-bit precision.
|
|
|
|
*/
|
|
|
|
bytespercyl = (off_t) sectorsize * fwheads * fwsectors;
|
|
|
|
fwcylinders = mediasize / bytespercyl;
|
|
|
|
#if defined(DEBUG)
|
|
|
|
linux_msg(td, "HDIO_GET_GEO: mediasize %jd, c/h/s %d/%d/%d, "
|
|
|
|
"bpc %jd",
|
2018-02-05 17:29:12 +00:00
|
|
|
(intmax_t)mediasize, fwcylinders, fwheads, fwsectors,
|
2004-06-14 07:26:23 +00:00
|
|
|
(intmax_t)bytespercyl);
|
|
|
|
#endif
|
|
|
|
if ((args->cmd & 0xffff) == LINUX_HDIO_GET_GEO) {
|
|
|
|
struct linux_hd_geometry hdg;
|
|
|
|
|
|
|
|
hdg.cylinders = fwcylinders;
|
|
|
|
hdg.heads = fwheads;
|
|
|
|
hdg.sectors = fwsectors;
|
|
|
|
hdg.start = 0;
|
|
|
|
error = copyout(&hdg, (void *)args->arg, sizeof(hdg));
|
|
|
|
} else if ((args->cmd & 0xffff) == LINUX_HDIO_GET_GEO_BIG) {
|
|
|
|
struct linux_hd_big_geometry hdbg;
|
|
|
|
|
2018-04-04 14:41:48 +00:00
|
|
|
memset(&hdbg, 0, sizeof(hdbg));
|
2004-06-14 07:26:23 +00:00
|
|
|
hdbg.cylinders = fwcylinders;
|
|
|
|
hdbg.heads = fwheads;
|
|
|
|
hdbg.sectors = fwsectors;
|
|
|
|
hdbg.start = 0;
|
|
|
|
error = copyout(&hdbg, (void *)args->arg, sizeof(hdbg));
|
|
|
|
}
|
|
|
|
return (error);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* XXX */
|
|
|
|
linux_msg(td,
|
|
|
|
"ioctl fd=%d, cmd=0x%x ('%c',%d) is not implemented",
|
|
|
|
args->fd, (int)(args->cmd & 0xffff),
|
|
|
|
(int)(args->cmd & 0xff00) >> 8,
|
|
|
|
(int)(args->cmd & 0xff));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
fdrop(fp, td);
|
|
|
|
return (ENOIOCTL);
|
|
|
|
}
|
|
|
|
|
2000-03-09 15:14:14 +00:00
|
|
|
static int
|
2001-09-12 08:38:13 +00:00
|
|
|
linux_ioctl_disk(struct thread *td, struct linux_ioctl_args *args)
|
2000-03-09 15:14:14 +00:00
|
|
|
{
|
Change the cap_rights_t type from uint64_t to a structure that we can extend
in the future in a backward compatible (API and ABI) way.
The cap_rights_t represents capability rights. We used to use one bit to
represent one right, but we are running out of spare bits. Currently the new
structure provides place for 114 rights (so 50 more than the previous
cap_rights_t), but it is possible to grow the structure to hold at least 285
rights, although we can make it even larger if 285 rights won't be enough.
The structure definition looks like this:
struct cap_rights {
uint64_t cr_rights[CAP_RIGHTS_VERSION + 2];
};
The initial CAP_RIGHTS_VERSION is 0.
The top two bits in the first element of the cr_rights[] array contain total
number of elements in the array - 2. This means if those two bits are equal to
0, we have 2 array elements.
The top two bits in all remaining array elements should be 0.
The next five bits in all array elements contain array index. Only one bit is
used and bit position in this five-bits range defines array index. This means
there can be at most five array elements in the future.
To define new right the CAPRIGHT() macro must be used. The macro takes two
arguments - an array index and a bit to set, eg.
#define CAP_PDKILL CAPRIGHT(1, 0x0000000000000800ULL)
We still support aliases that combine few rights, but the rights have to belong
to the same array element, eg:
#define CAP_LOOKUP CAPRIGHT(0, 0x0000000000000400ULL)
#define CAP_FCHMOD CAPRIGHT(0, 0x0000000000002000ULL)
#define CAP_FCHMODAT (CAP_FCHMOD | CAP_LOOKUP)
There is new API to manage the new cap_rights_t structure:
cap_rights_t *cap_rights_init(cap_rights_t *rights, ...);
void cap_rights_set(cap_rights_t *rights, ...);
void cap_rights_clear(cap_rights_t *rights, ...);
bool cap_rights_is_set(const cap_rights_t *rights, ...);
bool cap_rights_is_valid(const cap_rights_t *rights);
void cap_rights_merge(cap_rights_t *dst, const cap_rights_t *src);
void cap_rights_remove(cap_rights_t *dst, const cap_rights_t *src);
bool cap_rights_contains(const cap_rights_t *big, const cap_rights_t *little);
Capability rights to the cap_rights_init(), cap_rights_set(),
cap_rights_clear() and cap_rights_is_set() functions are provided by
separating them with commas, eg:
cap_rights_t rights;
cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_FSTAT);
There is no need to terminate the list of rights, as those functions are
actually macros that take care of the termination, eg:
#define cap_rights_set(rights, ...) \
__cap_rights_set((rights), __VA_ARGS__, 0ULL)
void __cap_rights_set(cap_rights_t *rights, ...);
Thanks to using one bit as an array index we can assert in those functions that
there are no two rights belonging to different array elements provided
together. For example this is illegal and will be detected, because CAP_LOOKUP
belongs to element 0 and CAP_PDKILL to element 1:
cap_rights_init(&rights, CAP_LOOKUP | CAP_PDKILL);
Providing several rights that belongs to the same array's element this way is
correct, but is not advised. It should only be used for aliases definition.
This commit also breaks compatibility with some existing Capsicum system calls,
but I see no other way to do that. This should be fine as Capsicum is still
experimental and this change is not going to 9.x.
Sponsored by: The FreeBSD Foundation
2013-09-05 00:09:56 +00:00
|
|
|
cap_rights_t rights;
|
2002-01-13 11:58:06 +00:00
|
|
|
struct file *fp;
|
2000-03-09 15:14:14 +00:00
|
|
|
int error;
|
2003-03-28 08:58:11 +00:00
|
|
|
u_int sectorsize;
|
|
|
|
off_t mediasize;
|
2000-03-09 15:14:14 +00:00
|
|
|
|
Change the cap_rights_t type from uint64_t to a structure that we can extend
in the future in a backward compatible (API and ABI) way.
The cap_rights_t represents capability rights. We used to use one bit to
represent one right, but we are running out of spare bits. Currently the new
structure provides place for 114 rights (so 50 more than the previous
cap_rights_t), but it is possible to grow the structure to hold at least 285
rights, although we can make it even larger if 285 rights won't be enough.
The structure definition looks like this:
struct cap_rights {
uint64_t cr_rights[CAP_RIGHTS_VERSION + 2];
};
The initial CAP_RIGHTS_VERSION is 0.
The top two bits in the first element of the cr_rights[] array contain total
number of elements in the array - 2. This means if those two bits are equal to
0, we have 2 array elements.
The top two bits in all remaining array elements should be 0.
The next five bits in all array elements contain array index. Only one bit is
used and bit position in this five-bits range defines array index. This means
there can be at most five array elements in the future.
To define new right the CAPRIGHT() macro must be used. The macro takes two
arguments - an array index and a bit to set, eg.
#define CAP_PDKILL CAPRIGHT(1, 0x0000000000000800ULL)
We still support aliases that combine few rights, but the rights have to belong
to the same array element, eg:
#define CAP_LOOKUP CAPRIGHT(0, 0x0000000000000400ULL)
#define CAP_FCHMOD CAPRIGHT(0, 0x0000000000002000ULL)
#define CAP_FCHMODAT (CAP_FCHMOD | CAP_LOOKUP)
There is new API to manage the new cap_rights_t structure:
cap_rights_t *cap_rights_init(cap_rights_t *rights, ...);
void cap_rights_set(cap_rights_t *rights, ...);
void cap_rights_clear(cap_rights_t *rights, ...);
bool cap_rights_is_set(const cap_rights_t *rights, ...);
bool cap_rights_is_valid(const cap_rights_t *rights);
void cap_rights_merge(cap_rights_t *dst, const cap_rights_t *src);
void cap_rights_remove(cap_rights_t *dst, const cap_rights_t *src);
bool cap_rights_contains(const cap_rights_t *big, const cap_rights_t *little);
Capability rights to the cap_rights_init(), cap_rights_set(),
cap_rights_clear() and cap_rights_is_set() functions are provided by
separating them with commas, eg:
cap_rights_t rights;
cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_FSTAT);
There is no need to terminate the list of rights, as those functions are
actually macros that take care of the termination, eg:
#define cap_rights_set(rights, ...) \
__cap_rights_set((rights), __VA_ARGS__, 0ULL)
void __cap_rights_set(cap_rights_t *rights, ...);
Thanks to using one bit as an array index we can assert in those functions that
there are no two rights belonging to different array elements provided
together. For example this is illegal and will be detected, because CAP_LOOKUP
belongs to element 0 and CAP_PDKILL to element 1:
cap_rights_init(&rights, CAP_LOOKUP | CAP_PDKILL);
Providing several rights that belongs to the same array's element this way is
correct, but is not advised. It should only be used for aliases definition.
This commit also breaks compatibility with some existing Capsicum system calls,
but I see no other way to do that. This should be fine as Capsicum is still
experimental and this change is not going to 9.x.
Sponsored by: The FreeBSD Foundation
2013-09-05 00:09:56 +00:00
|
|
|
error = fget(td, args->fd, cap_rights_init(&rights, CAP_IOCTL), &fp);
|
|
|
|
if (error != 0)
|
2002-01-14 00:13:45 +00:00
|
|
|
return (error);
|
2000-03-09 15:14:14 +00:00
|
|
|
switch (args->cmd & 0xffff) {
|
|
|
|
case LINUX_BLKGETSIZE:
|
2003-03-28 08:58:11 +00:00
|
|
|
error = fo_ioctl(fp, DIOCGSECTORSIZE,
|
|
|
|
(caddr_t)§orsize, td->td_ucred, td);
|
|
|
|
if (!error)
|
|
|
|
error = fo_ioctl(fp, DIOCGMEDIASIZE,
|
|
|
|
(caddr_t)&mediasize, td->td_ucred, td);
|
2002-01-13 11:58:06 +00:00
|
|
|
fdrop(fp, td);
|
2000-03-09 15:14:14 +00:00
|
|
|
if (error)
|
|
|
|
return (error);
|
2003-03-28 08:58:11 +00:00
|
|
|
sectorsize = mediasize / sectorsize;
|
|
|
|
/*
|
|
|
|
* XXX: How do we know we return the right size of integer ?
|
|
|
|
*/
|
|
|
|
return (copyout(§orsize, (void *)args->arg,
|
|
|
|
sizeof(sectorsize)));
|
2004-06-14 07:26:23 +00:00
|
|
|
break;
|
2016-09-17 08:10:01 +00:00
|
|
|
case LINUX_BLKSSZGET:
|
|
|
|
error = fo_ioctl(fp, DIOCGSECTORSIZE,
|
|
|
|
(caddr_t)§orsize, td->td_ucred, td);
|
|
|
|
fdrop(fp, td);
|
|
|
|
if (error)
|
|
|
|
return (error);
|
|
|
|
return (copyout(§orsize, (void *)args->arg,
|
|
|
|
sizeof(sectorsize)));
|
|
|
|
break;
|
2000-03-09 15:14:14 +00:00
|
|
|
}
|
2002-01-13 11:58:06 +00:00
|
|
|
fdrop(fp, td);
|
2000-03-09 15:14:14 +00:00
|
|
|
return (ENOIOCTL);
|
|
|
|
}
|
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
/*
|
|
|
|
* termio related ioctls
|
|
|
|
*/
|
1998-08-31 06:55:02 +00:00
|
|
|
|
1996-03-03 19:07:50 +00:00
|
|
|
struct linux_termio {
|
1999-12-04 11:10:22 +00:00
|
|
|
unsigned short c_iflag;
|
|
|
|
unsigned short c_oflag;
|
|
|
|
unsigned short c_cflag;
|
|
|
|
unsigned short c_lflag;
|
|
|
|
unsigned char c_line;
|
|
|
|
unsigned char c_cc[LINUX_NCC];
|
1996-03-03 19:07:50 +00:00
|
|
|
};
|
|
|
|
|
1995-06-25 17:32:43 +00:00
|
|
|
struct linux_termios {
|
1999-12-04 11:10:22 +00:00
|
|
|
unsigned int c_iflag;
|
|
|
|
unsigned int c_oflag;
|
|
|
|
unsigned int c_cflag;
|
|
|
|
unsigned int c_lflag;
|
|
|
|
unsigned char c_line;
|
|
|
|
unsigned char c_cc[LINUX_NCCS];
|
1995-06-25 17:32:43 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct linux_winsize {
|
1999-12-04 11:10:22 +00:00
|
|
|
unsigned short ws_row, ws_col;
|
|
|
|
unsigned short ws_xpixel, ws_ypixel;
|
1995-06-25 17:32:43 +00:00
|
|
|
};
|
|
|
|
|
Integrate the new MPSAFE TTY layer to the FreeBSD operating system.
The last half year I've been working on a replacement TTY layer for the
FreeBSD kernel. The new TTY layer was designed to improve the following:
- Improved driver model:
The old TTY layer has a driver model that is not abstract enough to
make it friendly to use. A good example is the output path, where the
device drivers directly access the output buffers. This means that an
in-kernel PPP implementation must always convert network buffers into
TTY buffers.
If a PPP implementation would be built on top of the new TTY layer
(still needs a hooks layer, though), it would allow the PPP
implementation to directly hand the data to the TTY driver.
- Improved hotplugging:
With the old TTY layer, it isn't entirely safe to destroy TTY's from
the system. This implementation has a two-step destructing design,
where the driver first abandons the TTY. After all threads have left
the TTY, the TTY layer calls a routine in the driver, which can be
used to free resources (unit numbers, etc).
The pts(4) driver also implements this feature, which means
posix_openpt() will now return PTY's that are created on the fly.
- Improved performance:
One of the major improvements is the per-TTY mutex, which is expected
to improve scalability when compared to the old Giant locking.
Another change is the unbuffered copying to userspace, which is both
used on TTY device nodes and PTY masters.
Upgrading should be quite straightforward. Unlike previous versions,
existing kernel configuration files do not need to be changed, except
when they reference device drivers that are listed in UPDATING.
Obtained from: //depot/projects/mpsafetty/...
Approved by: philip (ex-mentor)
Discussed: on the lists, at BSDCan, at the DevSummit
Sponsored by: Snow B.V., the Netherlands
dcons(4) fixed by: kan
2008-08-20 08:31:58 +00:00
|
|
|
struct speedtab {
|
|
|
|
int sp_speed; /* Speed. */
|
|
|
|
int sp_code; /* Code. */
|
|
|
|
};
|
|
|
|
|
1995-06-25 17:32:43 +00:00
|
|
|
static struct speedtab sptab[] = {
|
1999-12-04 11:10:22 +00:00
|
|
|
{ B0, LINUX_B0 }, { B50, LINUX_B50 },
|
|
|
|
{ B75, LINUX_B75 }, { B110, LINUX_B110 },
|
|
|
|
{ B134, LINUX_B134 }, { B150, LINUX_B150 },
|
|
|
|
{ B200, LINUX_B200 }, { B300, LINUX_B300 },
|
|
|
|
{ B600, LINUX_B600 }, { B1200, LINUX_B1200 },
|
|
|
|
{ B1800, LINUX_B1800 }, { B2400, LINUX_B2400 },
|
|
|
|
{ B4800, LINUX_B4800 }, { B9600, LINUX_B9600 },
|
|
|
|
{ B19200, LINUX_B19200 }, { B38400, LINUX_B38400 },
|
|
|
|
{ B57600, LINUX_B57600 }, { B115200, LINUX_B115200 },
|
|
|
|
{-1, -1 }
|
1995-06-25 17:32:43 +00:00
|
|
|
};
|
|
|
|
|
1996-03-10 22:30:53 +00:00
|
|
|
struct linux_serial_struct {
|
1999-12-04 11:10:22 +00:00
|
|
|
int type;
|
|
|
|
int line;
|
|
|
|
int port;
|
|
|
|
int irq;
|
|
|
|
int flags;
|
|
|
|
int xmit_fifo_size;
|
|
|
|
int custom_divisor;
|
|
|
|
int baud_base;
|
|
|
|
unsigned short close_delay;
|
|
|
|
char reserved_char[2];
|
|
|
|
int hub6;
|
|
|
|
unsigned short closing_wait;
|
|
|
|
unsigned short closing_wait2;
|
|
|
|
int reserved[4];
|
1996-03-10 22:30:53 +00:00
|
|
|
};
|
|
|
|
|
1995-06-25 17:32:43 +00:00
|
|
|
static int
|
|
|
|
linux_to_bsd_speed(int code, struct speedtab *table)
|
|
|
|
{
|
1999-12-04 11:10:22 +00:00
|
|
|
for ( ; table->sp_code != -1; table++)
|
|
|
|
if (table->sp_code == code)
|
|
|
|
return (table->sp_speed);
|
2018-03-12 15:35:24 +00:00
|
|
|
return (-1);
|
1995-06-25 17:32:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
bsd_to_linux_speed(int speed, struct speedtab *table)
|
|
|
|
{
|
1999-12-04 11:10:22 +00:00
|
|
|
for ( ; table->sp_speed != -1; table++)
|
|
|
|
if (table->sp_speed == speed)
|
|
|
|
return (table->sp_code);
|
2018-03-12 15:35:24 +00:00
|
|
|
return (-1);
|
1995-06-25 17:32:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
1999-12-04 11:10:22 +00:00
|
|
|
bsd_to_linux_termios(struct termios *bios, struct linux_termios *lios)
|
1995-06-25 17:32:43 +00:00
|
|
|
{
|
1999-12-04 11:10:22 +00:00
|
|
|
int i;
|
1995-06-25 17:32:43 +00:00
|
|
|
|
|
|
|
#ifdef DEBUG
|
2001-02-16 16:40:43 +00:00
|
|
|
if (ldebug(ioctl)) {
|
|
|
|
printf("LINUX: BSD termios structure (input):\n");
|
|
|
|
printf("i=%08x o=%08x c=%08x l=%08x ispeed=%d ospeed=%d\n",
|
|
|
|
bios->c_iflag, bios->c_oflag, bios->c_cflag, bios->c_lflag,
|
|
|
|
bios->c_ispeed, bios->c_ospeed);
|
|
|
|
printf("c_cc ");
|
|
|
|
for (i=0; i<NCCS; i++)
|
|
|
|
printf("%02x ", bios->c_cc[i]);
|
|
|
|
printf("\n");
|
|
|
|
}
|
1995-06-25 17:32:43 +00:00
|
|
|
#endif
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
lios->c_iflag = 0;
|
|
|
|
if (bios->c_iflag & IGNBRK)
|
|
|
|
lios->c_iflag |= LINUX_IGNBRK;
|
|
|
|
if (bios->c_iflag & BRKINT)
|
|
|
|
lios->c_iflag |= LINUX_BRKINT;
|
|
|
|
if (bios->c_iflag & IGNPAR)
|
|
|
|
lios->c_iflag |= LINUX_IGNPAR;
|
|
|
|
if (bios->c_iflag & PARMRK)
|
|
|
|
lios->c_iflag |= LINUX_PARMRK;
|
|
|
|
if (bios->c_iflag & INPCK)
|
|
|
|
lios->c_iflag |= LINUX_INPCK;
|
|
|
|
if (bios->c_iflag & ISTRIP)
|
|
|
|
lios->c_iflag |= LINUX_ISTRIP;
|
|
|
|
if (bios->c_iflag & INLCR)
|
|
|
|
lios->c_iflag |= LINUX_INLCR;
|
|
|
|
if (bios->c_iflag & IGNCR)
|
|
|
|
lios->c_iflag |= LINUX_IGNCR;
|
|
|
|
if (bios->c_iflag & ICRNL)
|
|
|
|
lios->c_iflag |= LINUX_ICRNL;
|
|
|
|
if (bios->c_iflag & IXON)
|
|
|
|
lios->c_iflag |= LINUX_IXON;
|
|
|
|
if (bios->c_iflag & IXANY)
|
|
|
|
lios->c_iflag |= LINUX_IXANY;
|
|
|
|
if (bios->c_iflag & IXOFF)
|
|
|
|
lios->c_iflag |= LINUX_IXOFF;
|
|
|
|
if (bios->c_iflag & IMAXBEL)
|
|
|
|
lios->c_iflag |= LINUX_IMAXBEL;
|
|
|
|
|
|
|
|
lios->c_oflag = 0;
|
|
|
|
if (bios->c_oflag & OPOST)
|
|
|
|
lios->c_oflag |= LINUX_OPOST;
|
|
|
|
if (bios->c_oflag & ONLCR)
|
|
|
|
lios->c_oflag |= LINUX_ONLCR;
|
Integrate the new MPSAFE TTY layer to the FreeBSD operating system.
The last half year I've been working on a replacement TTY layer for the
FreeBSD kernel. The new TTY layer was designed to improve the following:
- Improved driver model:
The old TTY layer has a driver model that is not abstract enough to
make it friendly to use. A good example is the output path, where the
device drivers directly access the output buffers. This means that an
in-kernel PPP implementation must always convert network buffers into
TTY buffers.
If a PPP implementation would be built on top of the new TTY layer
(still needs a hooks layer, though), it would allow the PPP
implementation to directly hand the data to the TTY driver.
- Improved hotplugging:
With the old TTY layer, it isn't entirely safe to destroy TTY's from
the system. This implementation has a two-step destructing design,
where the driver first abandons the TTY. After all threads have left
the TTY, the TTY layer calls a routine in the driver, which can be
used to free resources (unit numbers, etc).
The pts(4) driver also implements this feature, which means
posix_openpt() will now return PTY's that are created on the fly.
- Improved performance:
One of the major improvements is the per-TTY mutex, which is expected
to improve scalability when compared to the old Giant locking.
Another change is the unbuffered copying to userspace, which is both
used on TTY device nodes and PTY masters.
Upgrading should be quite straightforward. Unlike previous versions,
existing kernel configuration files do not need to be changed, except
when they reference device drivers that are listed in UPDATING.
Obtained from: //depot/projects/mpsafetty/...
Approved by: philip (ex-mentor)
Discussed: on the lists, at BSDCan, at the DevSummit
Sponsored by: Snow B.V., the Netherlands
dcons(4) fixed by: kan
2008-08-20 08:31:58 +00:00
|
|
|
if (bios->c_oflag & TAB3)
|
1999-12-04 11:10:22 +00:00
|
|
|
lios->c_oflag |= LINUX_XTABS;
|
|
|
|
|
|
|
|
lios->c_cflag = bsd_to_linux_speed(bios->c_ispeed, sptab);
|
|
|
|
lios->c_cflag |= (bios->c_cflag & CSIZE) >> 4;
|
|
|
|
if (bios->c_cflag & CSTOPB)
|
|
|
|
lios->c_cflag |= LINUX_CSTOPB;
|
|
|
|
if (bios->c_cflag & CREAD)
|
|
|
|
lios->c_cflag |= LINUX_CREAD;
|
|
|
|
if (bios->c_cflag & PARENB)
|
|
|
|
lios->c_cflag |= LINUX_PARENB;
|
|
|
|
if (bios->c_cflag & PARODD)
|
|
|
|
lios->c_cflag |= LINUX_PARODD;
|
|
|
|
if (bios->c_cflag & HUPCL)
|
|
|
|
lios->c_cflag |= LINUX_HUPCL;
|
|
|
|
if (bios->c_cflag & CLOCAL)
|
|
|
|
lios->c_cflag |= LINUX_CLOCAL;
|
|
|
|
if (bios->c_cflag & CRTSCTS)
|
|
|
|
lios->c_cflag |= LINUX_CRTSCTS;
|
|
|
|
|
|
|
|
lios->c_lflag = 0;
|
|
|
|
if (bios->c_lflag & ISIG)
|
|
|
|
lios->c_lflag |= LINUX_ISIG;
|
|
|
|
if (bios->c_lflag & ICANON)
|
|
|
|
lios->c_lflag |= LINUX_ICANON;
|
|
|
|
if (bios->c_lflag & ECHO)
|
|
|
|
lios->c_lflag |= LINUX_ECHO;
|
|
|
|
if (bios->c_lflag & ECHOE)
|
|
|
|
lios->c_lflag |= LINUX_ECHOE;
|
|
|
|
if (bios->c_lflag & ECHOK)
|
|
|
|
lios->c_lflag |= LINUX_ECHOK;
|
|
|
|
if (bios->c_lflag & ECHONL)
|
|
|
|
lios->c_lflag |= LINUX_ECHONL;
|
|
|
|
if (bios->c_lflag & NOFLSH)
|
|
|
|
lios->c_lflag |= LINUX_NOFLSH;
|
|
|
|
if (bios->c_lflag & TOSTOP)
|
|
|
|
lios->c_lflag |= LINUX_TOSTOP;
|
|
|
|
if (bios->c_lflag & ECHOCTL)
|
|
|
|
lios->c_lflag |= LINUX_ECHOCTL;
|
|
|
|
if (bios->c_lflag & ECHOPRT)
|
|
|
|
lios->c_lflag |= LINUX_ECHOPRT;
|
|
|
|
if (bios->c_lflag & ECHOKE)
|
|
|
|
lios->c_lflag |= LINUX_ECHOKE;
|
|
|
|
if (bios->c_lflag & FLUSHO)
|
|
|
|
lios->c_lflag |= LINUX_FLUSHO;
|
|
|
|
if (bios->c_lflag & PENDIN)
|
|
|
|
lios->c_lflag |= LINUX_PENDIN;
|
|
|
|
if (bios->c_lflag & IEXTEN)
|
|
|
|
lios->c_lflag |= LINUX_IEXTEN;
|
|
|
|
|
|
|
|
for (i=0; i<LINUX_NCCS; i++)
|
|
|
|
lios->c_cc[i] = LINUX_POSIX_VDISABLE;
|
|
|
|
lios->c_cc[LINUX_VINTR] = bios->c_cc[VINTR];
|
|
|
|
lios->c_cc[LINUX_VQUIT] = bios->c_cc[VQUIT];
|
|
|
|
lios->c_cc[LINUX_VERASE] = bios->c_cc[VERASE];
|
|
|
|
lios->c_cc[LINUX_VKILL] = bios->c_cc[VKILL];
|
|
|
|
lios->c_cc[LINUX_VEOF] = bios->c_cc[VEOF];
|
|
|
|
lios->c_cc[LINUX_VEOL] = bios->c_cc[VEOL];
|
|
|
|
lios->c_cc[LINUX_VMIN] = bios->c_cc[VMIN];
|
|
|
|
lios->c_cc[LINUX_VTIME] = bios->c_cc[VTIME];
|
|
|
|
lios->c_cc[LINUX_VEOL2] = bios->c_cc[VEOL2];
|
|
|
|
lios->c_cc[LINUX_VSUSP] = bios->c_cc[VSUSP];
|
|
|
|
lios->c_cc[LINUX_VSTART] = bios->c_cc[VSTART];
|
|
|
|
lios->c_cc[LINUX_VSTOP] = bios->c_cc[VSTOP];
|
|
|
|
lios->c_cc[LINUX_VREPRINT] = bios->c_cc[VREPRINT];
|
|
|
|
lios->c_cc[LINUX_VDISCARD] = bios->c_cc[VDISCARD];
|
|
|
|
lios->c_cc[LINUX_VWERASE] = bios->c_cc[VWERASE];
|
|
|
|
lios->c_cc[LINUX_VLNEXT] = bios->c_cc[VLNEXT];
|
|
|
|
|
|
|
|
for (i=0; i<LINUX_NCCS; i++) {
|
2003-06-28 19:32:07 +00:00
|
|
|
if (i != LINUX_VMIN && i != LINUX_VTIME &&
|
|
|
|
lios->c_cc[i] == _POSIX_VDISABLE)
|
1999-12-04 11:10:22 +00:00
|
|
|
lios->c_cc[i] = LINUX_POSIX_VDISABLE;
|
|
|
|
}
|
|
|
|
lios->c_line = 0;
|
|
|
|
|
1995-06-25 17:32:43 +00:00
|
|
|
#ifdef DEBUG
|
2001-02-16 16:40:43 +00:00
|
|
|
if (ldebug(ioctl)) {
|
|
|
|
printf("LINUX: LINUX termios structure (output):\n");
|
|
|
|
printf("i=%08x o=%08x c=%08x l=%08x line=%d\n",
|
|
|
|
lios->c_iflag, lios->c_oflag, lios->c_cflag,
|
|
|
|
lios->c_lflag, (int)lios->c_line);
|
|
|
|
printf("c_cc ");
|
2003-03-02 15:56:49 +00:00
|
|
|
for (i=0; i<LINUX_NCCS; i++)
|
2001-02-16 16:40:43 +00:00
|
|
|
printf("%02x ", lios->c_cc[i]);
|
|
|
|
printf("\n");
|
|
|
|
}
|
1995-06-25 17:32:43 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
1999-12-04 11:10:22 +00:00
|
|
|
linux_to_bsd_termios(struct linux_termios *lios, struct termios *bios)
|
1995-06-25 17:32:43 +00:00
|
|
|
{
|
1999-12-04 11:10:22 +00:00
|
|
|
int i;
|
|
|
|
|
1995-06-25 17:32:43 +00:00
|
|
|
#ifdef DEBUG
|
2001-02-16 16:40:43 +00:00
|
|
|
if (ldebug(ioctl)) {
|
|
|
|
printf("LINUX: LINUX termios structure (input):\n");
|
2003-03-02 15:56:49 +00:00
|
|
|
printf("i=%08x o=%08x c=%08x l=%08x line=%d\n",
|
2001-02-16 16:40:43 +00:00
|
|
|
lios->c_iflag, lios->c_oflag, lios->c_cflag,
|
|
|
|
lios->c_lflag, (int)lios->c_line);
|
|
|
|
printf("c_cc ");
|
|
|
|
for (i=0; i<LINUX_NCCS; i++)
|
|
|
|
printf("%02x ", lios->c_cc[i]);
|
|
|
|
printf("\n");
|
|
|
|
}
|
1995-06-25 17:32:43 +00:00
|
|
|
#endif
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
bios->c_iflag = 0;
|
|
|
|
if (lios->c_iflag & LINUX_IGNBRK)
|
|
|
|
bios->c_iflag |= IGNBRK;
|
|
|
|
if (lios->c_iflag & LINUX_BRKINT)
|
|
|
|
bios->c_iflag |= BRKINT;
|
|
|
|
if (lios->c_iflag & LINUX_IGNPAR)
|
|
|
|
bios->c_iflag |= IGNPAR;
|
|
|
|
if (lios->c_iflag & LINUX_PARMRK)
|
|
|
|
bios->c_iflag |= PARMRK;
|
|
|
|
if (lios->c_iflag & LINUX_INPCK)
|
|
|
|
bios->c_iflag |= INPCK;
|
|
|
|
if (lios->c_iflag & LINUX_ISTRIP)
|
|
|
|
bios->c_iflag |= ISTRIP;
|
|
|
|
if (lios->c_iflag & LINUX_INLCR)
|
|
|
|
bios->c_iflag |= INLCR;
|
|
|
|
if (lios->c_iflag & LINUX_IGNCR)
|
|
|
|
bios->c_iflag |= IGNCR;
|
|
|
|
if (lios->c_iflag & LINUX_ICRNL)
|
|
|
|
bios->c_iflag |= ICRNL;
|
|
|
|
if (lios->c_iflag & LINUX_IXON)
|
|
|
|
bios->c_iflag |= IXON;
|
|
|
|
if (lios->c_iflag & LINUX_IXANY)
|
|
|
|
bios->c_iflag |= IXANY;
|
|
|
|
if (lios->c_iflag & LINUX_IXOFF)
|
|
|
|
bios->c_iflag |= IXOFF;
|
|
|
|
if (lios->c_iflag & LINUX_IMAXBEL)
|
|
|
|
bios->c_iflag |= IMAXBEL;
|
|
|
|
|
|
|
|
bios->c_oflag = 0;
|
|
|
|
if (lios->c_oflag & LINUX_OPOST)
|
|
|
|
bios->c_oflag |= OPOST;
|
|
|
|
if (lios->c_oflag & LINUX_ONLCR)
|
|
|
|
bios->c_oflag |= ONLCR;
|
|
|
|
if (lios->c_oflag & LINUX_XTABS)
|
Integrate the new MPSAFE TTY layer to the FreeBSD operating system.
The last half year I've been working on a replacement TTY layer for the
FreeBSD kernel. The new TTY layer was designed to improve the following:
- Improved driver model:
The old TTY layer has a driver model that is not abstract enough to
make it friendly to use. A good example is the output path, where the
device drivers directly access the output buffers. This means that an
in-kernel PPP implementation must always convert network buffers into
TTY buffers.
If a PPP implementation would be built on top of the new TTY layer
(still needs a hooks layer, though), it would allow the PPP
implementation to directly hand the data to the TTY driver.
- Improved hotplugging:
With the old TTY layer, it isn't entirely safe to destroy TTY's from
the system. This implementation has a two-step destructing design,
where the driver first abandons the TTY. After all threads have left
the TTY, the TTY layer calls a routine in the driver, which can be
used to free resources (unit numbers, etc).
The pts(4) driver also implements this feature, which means
posix_openpt() will now return PTY's that are created on the fly.
- Improved performance:
One of the major improvements is the per-TTY mutex, which is expected
to improve scalability when compared to the old Giant locking.
Another change is the unbuffered copying to userspace, which is both
used on TTY device nodes and PTY masters.
Upgrading should be quite straightforward. Unlike previous versions,
existing kernel configuration files do not need to be changed, except
when they reference device drivers that are listed in UPDATING.
Obtained from: //depot/projects/mpsafetty/...
Approved by: philip (ex-mentor)
Discussed: on the lists, at BSDCan, at the DevSummit
Sponsored by: Snow B.V., the Netherlands
dcons(4) fixed by: kan
2008-08-20 08:31:58 +00:00
|
|
|
bios->c_oflag |= TAB3;
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
bios->c_cflag = (lios->c_cflag & LINUX_CSIZE) << 4;
|
|
|
|
if (lios->c_cflag & LINUX_CSTOPB)
|
|
|
|
bios->c_cflag |= CSTOPB;
|
|
|
|
if (lios->c_cflag & LINUX_CREAD)
|
|
|
|
bios->c_cflag |= CREAD;
|
|
|
|
if (lios->c_cflag & LINUX_PARENB)
|
|
|
|
bios->c_cflag |= PARENB;
|
|
|
|
if (lios->c_cflag & LINUX_PARODD)
|
|
|
|
bios->c_cflag |= PARODD;
|
|
|
|
if (lios->c_cflag & LINUX_HUPCL)
|
|
|
|
bios->c_cflag |= HUPCL;
|
|
|
|
if (lios->c_cflag & LINUX_CLOCAL)
|
|
|
|
bios->c_cflag |= CLOCAL;
|
|
|
|
if (lios->c_cflag & LINUX_CRTSCTS)
|
|
|
|
bios->c_cflag |= CRTSCTS;
|
|
|
|
|
|
|
|
bios->c_lflag = 0;
|
|
|
|
if (lios->c_lflag & LINUX_ISIG)
|
|
|
|
bios->c_lflag |= ISIG;
|
|
|
|
if (lios->c_lflag & LINUX_ICANON)
|
|
|
|
bios->c_lflag |= ICANON;
|
|
|
|
if (lios->c_lflag & LINUX_ECHO)
|
|
|
|
bios->c_lflag |= ECHO;
|
|
|
|
if (lios->c_lflag & LINUX_ECHOE)
|
|
|
|
bios->c_lflag |= ECHOE;
|
|
|
|
if (lios->c_lflag & LINUX_ECHOK)
|
|
|
|
bios->c_lflag |= ECHOK;
|
|
|
|
if (lios->c_lflag & LINUX_ECHONL)
|
|
|
|
bios->c_lflag |= ECHONL;
|
|
|
|
if (lios->c_lflag & LINUX_NOFLSH)
|
|
|
|
bios->c_lflag |= NOFLSH;
|
|
|
|
if (lios->c_lflag & LINUX_TOSTOP)
|
|
|
|
bios->c_lflag |= TOSTOP;
|
|
|
|
if (lios->c_lflag & LINUX_ECHOCTL)
|
|
|
|
bios->c_lflag |= ECHOCTL;
|
|
|
|
if (lios->c_lflag & LINUX_ECHOPRT)
|
|
|
|
bios->c_lflag |= ECHOPRT;
|
|
|
|
if (lios->c_lflag & LINUX_ECHOKE)
|
|
|
|
bios->c_lflag |= ECHOKE;
|
|
|
|
if (lios->c_lflag & LINUX_FLUSHO)
|
|
|
|
bios->c_lflag |= FLUSHO;
|
|
|
|
if (lios->c_lflag & LINUX_PENDIN)
|
|
|
|
bios->c_lflag |= PENDIN;
|
|
|
|
if (lios->c_lflag & LINUX_IEXTEN)
|
|
|
|
bios->c_lflag |= IEXTEN;
|
|
|
|
|
|
|
|
for (i=0; i<NCCS; i++)
|
|
|
|
bios->c_cc[i] = _POSIX_VDISABLE;
|
|
|
|
bios->c_cc[VINTR] = lios->c_cc[LINUX_VINTR];
|
|
|
|
bios->c_cc[VQUIT] = lios->c_cc[LINUX_VQUIT];
|
|
|
|
bios->c_cc[VERASE] = lios->c_cc[LINUX_VERASE];
|
|
|
|
bios->c_cc[VKILL] = lios->c_cc[LINUX_VKILL];
|
|
|
|
bios->c_cc[VEOF] = lios->c_cc[LINUX_VEOF];
|
|
|
|
bios->c_cc[VEOL] = lios->c_cc[LINUX_VEOL];
|
|
|
|
bios->c_cc[VMIN] = lios->c_cc[LINUX_VMIN];
|
|
|
|
bios->c_cc[VTIME] = lios->c_cc[LINUX_VTIME];
|
|
|
|
bios->c_cc[VEOL2] = lios->c_cc[LINUX_VEOL2];
|
|
|
|
bios->c_cc[VSUSP] = lios->c_cc[LINUX_VSUSP];
|
|
|
|
bios->c_cc[VSTART] = lios->c_cc[LINUX_VSTART];
|
|
|
|
bios->c_cc[VSTOP] = lios->c_cc[LINUX_VSTOP];
|
|
|
|
bios->c_cc[VREPRINT] = lios->c_cc[LINUX_VREPRINT];
|
|
|
|
bios->c_cc[VDISCARD] = lios->c_cc[LINUX_VDISCARD];
|
|
|
|
bios->c_cc[VWERASE] = lios->c_cc[LINUX_VWERASE];
|
|
|
|
bios->c_cc[VLNEXT] = lios->c_cc[LINUX_VLNEXT];
|
|
|
|
|
|
|
|
for (i=0; i<NCCS; i++) {
|
2003-06-28 19:32:07 +00:00
|
|
|
if (i != VMIN && i != VTIME &&
|
|
|
|
bios->c_cc[i] == LINUX_POSIX_VDISABLE)
|
1999-12-04 11:10:22 +00:00
|
|
|
bios->c_cc[i] = _POSIX_VDISABLE;
|
|
|
|
}
|
|
|
|
|
|
|
|
bios->c_ispeed = bios->c_ospeed =
|
|
|
|
linux_to_bsd_speed(lios->c_cflag & LINUX_CBAUD, sptab);
|
|
|
|
|
1995-06-25 17:32:43 +00:00
|
|
|
#ifdef DEBUG
|
2001-02-16 16:40:43 +00:00
|
|
|
if (ldebug(ioctl)) {
|
|
|
|
printf("LINUX: BSD termios structure (output):\n");
|
|
|
|
printf("i=%08x o=%08x c=%08x l=%08x ispeed=%d ospeed=%d\n",
|
|
|
|
bios->c_iflag, bios->c_oflag, bios->c_cflag, bios->c_lflag,
|
|
|
|
bios->c_ispeed, bios->c_ospeed);
|
|
|
|
printf("c_cc ");
|
2003-03-02 15:56:49 +00:00
|
|
|
for (i=0; i<NCCS; i++)
|
2001-02-16 16:40:43 +00:00
|
|
|
printf("%02x ", bios->c_cc[i]);
|
|
|
|
printf("\n");
|
|
|
|
}
|
1995-06-25 17:32:43 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
1996-03-03 19:07:50 +00:00
|
|
|
static void
|
1999-12-04 11:10:22 +00:00
|
|
|
bsd_to_linux_termio(struct termios *bios, struct linux_termio *lio)
|
1996-03-03 19:07:50 +00:00
|
|
|
{
|
1999-12-04 11:10:22 +00:00
|
|
|
struct linux_termios lios;
|
|
|
|
|
|
|
|
bsd_to_linux_termios(bios, &lios);
|
|
|
|
lio->c_iflag = lios.c_iflag;
|
|
|
|
lio->c_oflag = lios.c_oflag;
|
|
|
|
lio->c_cflag = lios.c_cflag;
|
|
|
|
lio->c_lflag = lios.c_lflag;
|
|
|
|
lio->c_line = lios.c_line;
|
|
|
|
memcpy(lio->c_cc, lios.c_cc, LINUX_NCC);
|
1996-03-03 19:07:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
1999-12-04 11:10:22 +00:00
|
|
|
linux_to_bsd_termio(struct linux_termio *lio, struct termios *bios)
|
|
|
|
{
|
|
|
|
struct linux_termios lios;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
lios.c_iflag = lio->c_iflag;
|
|
|
|
lios.c_oflag = lio->c_oflag;
|
|
|
|
lios.c_cflag = lio->c_cflag;
|
|
|
|
lios.c_lflag = lio->c_lflag;
|
|
|
|
for (i=LINUX_NCC; i<LINUX_NCCS; i++)
|
|
|
|
lios.c_cc[i] = LINUX_POSIX_VDISABLE;
|
|
|
|
memcpy(lios.c_cc, lio->c_cc, LINUX_NCC);
|
|
|
|
linux_to_bsd_termios(&lios, bios);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2001-09-12 08:38:13 +00:00
|
|
|
linux_ioctl_termio(struct thread *td, struct linux_ioctl_args *args)
|
1996-03-03 19:07:50 +00:00
|
|
|
{
|
1999-12-04 11:10:22 +00:00
|
|
|
struct termios bios;
|
|
|
|
struct linux_termios lios;
|
|
|
|
struct linux_termio lio;
|
Change the cap_rights_t type from uint64_t to a structure that we can extend
in the future in a backward compatible (API and ABI) way.
The cap_rights_t represents capability rights. We used to use one bit to
represent one right, but we are running out of spare bits. Currently the new
structure provides place for 114 rights (so 50 more than the previous
cap_rights_t), but it is possible to grow the structure to hold at least 285
rights, although we can make it even larger if 285 rights won't be enough.
The structure definition looks like this:
struct cap_rights {
uint64_t cr_rights[CAP_RIGHTS_VERSION + 2];
};
The initial CAP_RIGHTS_VERSION is 0.
The top two bits in the first element of the cr_rights[] array contain total
number of elements in the array - 2. This means if those two bits are equal to
0, we have 2 array elements.
The top two bits in all remaining array elements should be 0.
The next five bits in all array elements contain array index. Only one bit is
used and bit position in this five-bits range defines array index. This means
there can be at most five array elements in the future.
To define new right the CAPRIGHT() macro must be used. The macro takes two
arguments - an array index and a bit to set, eg.
#define CAP_PDKILL CAPRIGHT(1, 0x0000000000000800ULL)
We still support aliases that combine few rights, but the rights have to belong
to the same array element, eg:
#define CAP_LOOKUP CAPRIGHT(0, 0x0000000000000400ULL)
#define CAP_FCHMOD CAPRIGHT(0, 0x0000000000002000ULL)
#define CAP_FCHMODAT (CAP_FCHMOD | CAP_LOOKUP)
There is new API to manage the new cap_rights_t structure:
cap_rights_t *cap_rights_init(cap_rights_t *rights, ...);
void cap_rights_set(cap_rights_t *rights, ...);
void cap_rights_clear(cap_rights_t *rights, ...);
bool cap_rights_is_set(const cap_rights_t *rights, ...);
bool cap_rights_is_valid(const cap_rights_t *rights);
void cap_rights_merge(cap_rights_t *dst, const cap_rights_t *src);
void cap_rights_remove(cap_rights_t *dst, const cap_rights_t *src);
bool cap_rights_contains(const cap_rights_t *big, const cap_rights_t *little);
Capability rights to the cap_rights_init(), cap_rights_set(),
cap_rights_clear() and cap_rights_is_set() functions are provided by
separating them with commas, eg:
cap_rights_t rights;
cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_FSTAT);
There is no need to terminate the list of rights, as those functions are
actually macros that take care of the termination, eg:
#define cap_rights_set(rights, ...) \
__cap_rights_set((rights), __VA_ARGS__, 0ULL)
void __cap_rights_set(cap_rights_t *rights, ...);
Thanks to using one bit as an array index we can assert in those functions that
there are no two rights belonging to different array elements provided
together. For example this is illegal and will be detected, because CAP_LOOKUP
belongs to element 0 and CAP_PDKILL to element 1:
cap_rights_init(&rights, CAP_LOOKUP | CAP_PDKILL);
Providing several rights that belongs to the same array's element this way is
correct, but is not advised. It should only be used for aliases definition.
This commit also breaks compatibility with some existing Capsicum system calls,
but I see no other way to do that. This should be fine as Capsicum is still
experimental and this change is not going to 9.x.
Sponsored by: The FreeBSD Foundation
2013-09-05 00:09:56 +00:00
|
|
|
cap_rights_t rights;
|
2002-01-13 11:58:06 +00:00
|
|
|
struct file *fp;
|
1999-12-04 11:10:22 +00:00
|
|
|
int error;
|
|
|
|
|
Change the cap_rights_t type from uint64_t to a structure that we can extend
in the future in a backward compatible (API and ABI) way.
The cap_rights_t represents capability rights. We used to use one bit to
represent one right, but we are running out of spare bits. Currently the new
structure provides place for 114 rights (so 50 more than the previous
cap_rights_t), but it is possible to grow the structure to hold at least 285
rights, although we can make it even larger if 285 rights won't be enough.
The structure definition looks like this:
struct cap_rights {
uint64_t cr_rights[CAP_RIGHTS_VERSION + 2];
};
The initial CAP_RIGHTS_VERSION is 0.
The top two bits in the first element of the cr_rights[] array contain total
number of elements in the array - 2. This means if those two bits are equal to
0, we have 2 array elements.
The top two bits in all remaining array elements should be 0.
The next five bits in all array elements contain array index. Only one bit is
used and bit position in this five-bits range defines array index. This means
there can be at most five array elements in the future.
To define new right the CAPRIGHT() macro must be used. The macro takes two
arguments - an array index and a bit to set, eg.
#define CAP_PDKILL CAPRIGHT(1, 0x0000000000000800ULL)
We still support aliases that combine few rights, but the rights have to belong
to the same array element, eg:
#define CAP_LOOKUP CAPRIGHT(0, 0x0000000000000400ULL)
#define CAP_FCHMOD CAPRIGHT(0, 0x0000000000002000ULL)
#define CAP_FCHMODAT (CAP_FCHMOD | CAP_LOOKUP)
There is new API to manage the new cap_rights_t structure:
cap_rights_t *cap_rights_init(cap_rights_t *rights, ...);
void cap_rights_set(cap_rights_t *rights, ...);
void cap_rights_clear(cap_rights_t *rights, ...);
bool cap_rights_is_set(const cap_rights_t *rights, ...);
bool cap_rights_is_valid(const cap_rights_t *rights);
void cap_rights_merge(cap_rights_t *dst, const cap_rights_t *src);
void cap_rights_remove(cap_rights_t *dst, const cap_rights_t *src);
bool cap_rights_contains(const cap_rights_t *big, const cap_rights_t *little);
Capability rights to the cap_rights_init(), cap_rights_set(),
cap_rights_clear() and cap_rights_is_set() functions are provided by
separating them with commas, eg:
cap_rights_t rights;
cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_FSTAT);
There is no need to terminate the list of rights, as those functions are
actually macros that take care of the termination, eg:
#define cap_rights_set(rights, ...) \
__cap_rights_set((rights), __VA_ARGS__, 0ULL)
void __cap_rights_set(cap_rights_t *rights, ...);
Thanks to using one bit as an array index we can assert in those functions that
there are no two rights belonging to different array elements provided
together. For example this is illegal and will be detected, because CAP_LOOKUP
belongs to element 0 and CAP_PDKILL to element 1:
cap_rights_init(&rights, CAP_LOOKUP | CAP_PDKILL);
Providing several rights that belongs to the same array's element this way is
correct, but is not advised. It should only be used for aliases definition.
This commit also breaks compatibility with some existing Capsicum system calls,
but I see no other way to do that. This should be fine as Capsicum is still
experimental and this change is not going to 9.x.
Sponsored by: The FreeBSD Foundation
2013-09-05 00:09:56 +00:00
|
|
|
error = fget(td, args->fd, cap_rights_init(&rights, CAP_IOCTL), &fp);
|
|
|
|
if (error != 0)
|
2002-01-14 00:13:45 +00:00
|
|
|
return (error);
|
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
switch (args->cmd & 0xffff) {
|
|
|
|
|
|
|
|
case LINUX_TCGETS:
|
2002-08-17 02:36:16 +00:00
|
|
|
error = fo_ioctl(fp, TIOCGETA, (caddr_t)&bios, td->td_ucred,
|
|
|
|
td);
|
1999-12-04 11:10:22 +00:00
|
|
|
if (error)
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
bsd_to_linux_termios(&bios, &lios);
|
2003-03-03 09:14:26 +00:00
|
|
|
error = copyout(&lios, (void *)args->arg, sizeof(lios));
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
case LINUX_TCSETS:
|
2003-03-03 09:14:26 +00:00
|
|
|
error = copyin((void *)args->arg, &lios, sizeof(lios));
|
1999-12-04 11:10:22 +00:00
|
|
|
if (error)
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
linux_to_bsd_termios(&lios, &bios);
|
2002-08-17 02:36:16 +00:00
|
|
|
error = (fo_ioctl(fp, TIOCSETA, (caddr_t)&bios, td->td_ucred,
|
|
|
|
td));
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
case LINUX_TCSETSW:
|
2003-03-03 09:14:26 +00:00
|
|
|
error = copyin((void *)args->arg, &lios, sizeof(lios));
|
1999-12-04 11:10:22 +00:00
|
|
|
if (error)
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
linux_to_bsd_termios(&lios, &bios);
|
2002-08-17 02:36:16 +00:00
|
|
|
error = (fo_ioctl(fp, TIOCSETAW, (caddr_t)&bios, td->td_ucred,
|
|
|
|
td));
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
case LINUX_TCSETSF:
|
2003-03-03 09:14:26 +00:00
|
|
|
error = copyin((void *)args->arg, &lios, sizeof(lios));
|
1999-12-04 11:10:22 +00:00
|
|
|
if (error)
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
linux_to_bsd_termios(&lios, &bios);
|
2002-08-17 02:36:16 +00:00
|
|
|
error = (fo_ioctl(fp, TIOCSETAF, (caddr_t)&bios, td->td_ucred,
|
|
|
|
td));
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
case LINUX_TCGETA:
|
2002-08-17 02:36:16 +00:00
|
|
|
error = fo_ioctl(fp, TIOCGETA, (caddr_t)&bios, td->td_ucred,
|
|
|
|
td);
|
1999-12-04 11:10:22 +00:00
|
|
|
if (error)
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
bsd_to_linux_termio(&bios, &lio);
|
2003-03-03 09:14:26 +00:00
|
|
|
error = (copyout(&lio, (void *)args->arg, sizeof(lio)));
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
case LINUX_TCSETA:
|
2003-03-03 09:14:26 +00:00
|
|
|
error = copyin((void *)args->arg, &lio, sizeof(lio));
|
1999-12-04 11:10:22 +00:00
|
|
|
if (error)
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
linux_to_bsd_termio(&lio, &bios);
|
2002-08-17 02:36:16 +00:00
|
|
|
error = (fo_ioctl(fp, TIOCSETA, (caddr_t)&bios, td->td_ucred,
|
|
|
|
td));
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
case LINUX_TCSETAW:
|
2003-03-03 09:14:26 +00:00
|
|
|
error = copyin((void *)args->arg, &lio, sizeof(lio));
|
1999-12-04 11:10:22 +00:00
|
|
|
if (error)
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
linux_to_bsd_termio(&lio, &bios);
|
2002-08-17 02:36:16 +00:00
|
|
|
error = (fo_ioctl(fp, TIOCSETAW, (caddr_t)&bios, td->td_ucred,
|
|
|
|
td));
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
case LINUX_TCSETAF:
|
2003-03-03 09:14:26 +00:00
|
|
|
error = copyin((void *)args->arg, &lio, sizeof(lio));
|
1999-12-04 11:10:22 +00:00
|
|
|
if (error)
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
linux_to_bsd_termio(&lio, &bios);
|
2002-08-17 02:36:16 +00:00
|
|
|
error = (fo_ioctl(fp, TIOCSETAF, (caddr_t)&bios, td->td_ucred,
|
|
|
|
td));
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
/* LINUX_TCSBRK */
|
|
|
|
|
|
|
|
case LINUX_TCXONC: {
|
|
|
|
switch (args->arg) {
|
|
|
|
case LINUX_TCOOFF:
|
|
|
|
args->cmd = TIOCSTOP;
|
|
|
|
break;
|
|
|
|
case LINUX_TCOON:
|
|
|
|
args->cmd = TIOCSTART;
|
|
|
|
break;
|
|
|
|
case LINUX_TCIOFF:
|
|
|
|
case LINUX_TCION: {
|
|
|
|
int c;
|
|
|
|
struct write_args wr;
|
2002-08-17 02:36:16 +00:00
|
|
|
error = fo_ioctl(fp, TIOCGETA, (caddr_t)&bios,
|
|
|
|
td->td_ucred, td);
|
1999-12-04 11:10:22 +00:00
|
|
|
if (error)
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
|
|
|
fdrop(fp, td);
|
1999-12-04 11:10:22 +00:00
|
|
|
c = (args->arg == LINUX_TCIOFF) ? VSTOP : VSTART;
|
|
|
|
c = bios.c_cc[c];
|
|
|
|
if (c != _POSIX_VDISABLE) {
|
|
|
|
wr.fd = args->fd;
|
|
|
|
wr.buf = &c;
|
|
|
|
wr.nbyte = sizeof(c);
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_write(td, &wr));
|
1999-12-04 11:10:22 +00:00
|
|
|
} else
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
default:
|
2002-01-13 11:58:06 +00:00
|
|
|
fdrop(fp, td);
|
1999-12-04 11:10:22 +00:00
|
|
|
return (EINVAL);
|
|
|
|
}
|
|
|
|
args->arg = 0;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = (sys_ioctl(td, (struct ioctl_args *)args));
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
case LINUX_TCFLSH: {
|
2005-12-13 15:32:52 +00:00
|
|
|
int val;
|
1999-12-04 11:10:22 +00:00
|
|
|
switch (args->arg) {
|
|
|
|
case LINUX_TCIFLUSH:
|
2005-12-13 15:32:52 +00:00
|
|
|
val = FREAD;
|
1999-12-04 11:10:22 +00:00
|
|
|
break;
|
|
|
|
case LINUX_TCOFLUSH:
|
2005-12-13 15:32:52 +00:00
|
|
|
val = FWRITE;
|
1999-12-04 11:10:22 +00:00
|
|
|
break;
|
|
|
|
case LINUX_TCIOFLUSH:
|
2005-12-13 15:32:52 +00:00
|
|
|
val = FREAD | FWRITE;
|
1999-12-04 11:10:22 +00:00
|
|
|
break;
|
|
|
|
default:
|
2002-01-13 11:58:06 +00:00
|
|
|
fdrop(fp, td);
|
1999-12-04 11:10:22 +00:00
|
|
|
return (EINVAL);
|
|
|
|
}
|
2005-12-13 15:32:52 +00:00
|
|
|
error = (fo_ioctl(fp,TIOCFLUSH,(caddr_t)&val,td->td_ucred,td));
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
case LINUX_TIOCEXCL:
|
|
|
|
args->cmd = TIOCEXCL;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = (sys_ioctl(td, (struct ioctl_args *)args));
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
case LINUX_TIOCNXCL:
|
|
|
|
args->cmd = TIOCNXCL;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = (sys_ioctl(td, (struct ioctl_args *)args));
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
|
2002-09-05 02:51:25 +00:00
|
|
|
case LINUX_TIOCSCTTY:
|
|
|
|
args->cmd = TIOCSCTTY;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = (sys_ioctl(td, (struct ioctl_args *)args));
|
2002-09-05 02:51:25 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
case LINUX_TIOCGPGRP:
|
|
|
|
args->cmd = TIOCGPGRP;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = (sys_ioctl(td, (struct ioctl_args *)args));
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
case LINUX_TIOCSPGRP:
|
|
|
|
args->cmd = TIOCSPGRP;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = (sys_ioctl(td, (struct ioctl_args *)args));
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
/* LINUX_TIOCOUTQ */
|
|
|
|
/* LINUX_TIOCSTI */
|
|
|
|
|
|
|
|
case LINUX_TIOCGWINSZ:
|
|
|
|
args->cmd = TIOCGWINSZ;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = (sys_ioctl(td, (struct ioctl_args *)args));
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
case LINUX_TIOCSWINSZ:
|
|
|
|
args->cmd = TIOCSWINSZ;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = (sys_ioctl(td, (struct ioctl_args *)args));
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
case LINUX_TIOCMGET:
|
|
|
|
args->cmd = TIOCMGET;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = (sys_ioctl(td, (struct ioctl_args *)args));
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1996-03-03 19:07:50 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
case LINUX_TIOCMBIS:
|
|
|
|
args->cmd = TIOCMBIS;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = (sys_ioctl(td, (struct ioctl_args *)args));
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1996-03-03 19:07:50 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
case LINUX_TIOCMBIC:
|
|
|
|
args->cmd = TIOCMBIC;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = (sys_ioctl(td, (struct ioctl_args *)args));
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1996-03-03 19:07:50 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
case LINUX_TIOCMSET:
|
|
|
|
args->cmd = TIOCMSET;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = (sys_ioctl(td, (struct ioctl_args *)args));
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
/* TIOCGSOFTCAR */
|
|
|
|
/* TIOCSSOFTCAR */
|
|
|
|
|
|
|
|
case LINUX_FIONREAD: /* LINUX_TIOCINQ */
|
|
|
|
args->cmd = FIONREAD;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = (sys_ioctl(td, (struct ioctl_args *)args));
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
/* LINUX_TIOCLINUX */
|
|
|
|
|
|
|
|
case LINUX_TIOCCONS:
|
|
|
|
args->cmd = TIOCCONS;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = (sys_ioctl(td, (struct ioctl_args *)args));
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
case LINUX_TIOCGSERIAL: {
|
|
|
|
struct linux_serial_struct lss;
|
2016-05-31 16:56:30 +00:00
|
|
|
|
|
|
|
bzero(&lss, sizeof(lss));
|
1999-12-04 11:10:22 +00:00
|
|
|
lss.type = LINUX_PORT_16550A;
|
|
|
|
lss.flags = 0;
|
|
|
|
lss.close_delay = 0;
|
2003-03-03 09:14:26 +00:00
|
|
|
error = copyout(&lss, (void *)args->arg, sizeof(lss));
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
case LINUX_TIOCSSERIAL: {
|
|
|
|
struct linux_serial_struct lss;
|
2003-03-03 09:14:26 +00:00
|
|
|
error = copyin((void *)args->arg, &lss, sizeof(lss));
|
1999-12-04 11:10:22 +00:00
|
|
|
if (error)
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
/* XXX - It really helps to have an implementation that
|
|
|
|
* does nothing. NOT!
|
|
|
|
*/
|
2002-01-13 11:58:06 +00:00
|
|
|
error = 0;
|
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
}
|
|
|
|
|
2008-07-23 17:47:44 +00:00
|
|
|
case LINUX_TIOCPKT:
|
|
|
|
args->cmd = TIOCPKT;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = (sys_ioctl(td, (struct ioctl_args *)args));
|
2008-07-23 17:47:44 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
case LINUX_FIONBIO:
|
|
|
|
args->cmd = FIONBIO;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = (sys_ioctl(td, (struct ioctl_args *)args));
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
case LINUX_TIOCNOTTY:
|
|
|
|
args->cmd = TIOCNOTTY;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = (sys_ioctl(td, (struct ioctl_args *)args));
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
case LINUX_TIOCSETD: {
|
|
|
|
int line;
|
|
|
|
switch (args->arg) {
|
|
|
|
case LINUX_N_TTY:
|
|
|
|
line = TTYDISC;
|
|
|
|
break;
|
|
|
|
case LINUX_N_SLIP:
|
|
|
|
line = SLIPDISC;
|
|
|
|
break;
|
|
|
|
case LINUX_N_PPP:
|
|
|
|
line = PPPDISC;
|
|
|
|
break;
|
|
|
|
default:
|
2002-01-13 11:58:06 +00:00
|
|
|
fdrop(fp, td);
|
1999-12-04 11:10:22 +00:00
|
|
|
return (EINVAL);
|
|
|
|
}
|
2002-08-17 02:36:16 +00:00
|
|
|
error = (fo_ioctl(fp, TIOCSETD, (caddr_t)&line, td->td_ucred,
|
|
|
|
td));
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
case LINUX_TIOCGETD: {
|
|
|
|
int linux_line;
|
|
|
|
int bsd_line = TTYDISC;
|
2002-08-17 02:36:16 +00:00
|
|
|
error = fo_ioctl(fp, TIOCGETD, (caddr_t)&bsd_line,
|
|
|
|
td->td_ucred, td);
|
1999-12-04 11:10:22 +00:00
|
|
|
if (error)
|
2016-05-24 05:29:41 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
switch (bsd_line) {
|
|
|
|
case TTYDISC:
|
|
|
|
linux_line = LINUX_N_TTY;
|
|
|
|
break;
|
|
|
|
case SLIPDISC:
|
|
|
|
linux_line = LINUX_N_SLIP;
|
|
|
|
break;
|
|
|
|
case PPPDISC:
|
|
|
|
linux_line = LINUX_N_PPP;
|
|
|
|
break;
|
|
|
|
default:
|
2002-01-13 11:58:06 +00:00
|
|
|
fdrop(fp, td);
|
1999-12-04 11:10:22 +00:00
|
|
|
return (EINVAL);
|
|
|
|
}
|
2003-03-03 09:14:26 +00:00
|
|
|
error = (copyout(&linux_line, (void *)args->arg, sizeof(int)));
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* LINUX_TCSBRKP */
|
|
|
|
/* LINUX_TIOCTTYGSTRUCT */
|
|
|
|
|
|
|
|
case LINUX_FIONCLEX:
|
|
|
|
args->cmd = FIONCLEX;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = (sys_ioctl(td, (struct ioctl_args *)args));
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
case LINUX_FIOCLEX:
|
|
|
|
args->cmd = FIOCLEX;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = (sys_ioctl(td, (struct ioctl_args *)args));
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
case LINUX_FIOASYNC:
|
|
|
|
args->cmd = FIOASYNC;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = (sys_ioctl(td, (struct ioctl_args *)args));
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
/* LINUX_TIOCSERCONFIG */
|
|
|
|
/* LINUX_TIOCSERGWILD */
|
|
|
|
/* LINUX_TIOCSERSWILD */
|
|
|
|
/* LINUX_TIOCGLCKTRMIOS */
|
|
|
|
/* LINUX_TIOCSLCKTRMIOS */
|
|
|
|
|
2004-02-19 12:38:12 +00:00
|
|
|
case LINUX_TIOCSBRK:
|
|
|
|
args->cmd = TIOCSBRK;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = (sys_ioctl(td, (struct ioctl_args *)args));
|
2004-02-19 12:38:12 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case LINUX_TIOCCBRK:
|
|
|
|
args->cmd = TIOCCBRK;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = (sys_ioctl(td, (struct ioctl_args *)args));
|
2004-02-19 12:38:12 +00:00
|
|
|
break;
|
2006-01-26 01:32:46 +00:00
|
|
|
case LINUX_TIOCGPTN: {
|
|
|
|
int nb;
|
2018-02-05 17:29:12 +00:00
|
|
|
|
2006-01-26 01:32:46 +00:00
|
|
|
error = fo_ioctl(fp, TIOCGPTN, (caddr_t)&nb, td->td_ucred, td);
|
|
|
|
if (!error)
|
|
|
|
error = copyout(&nb, (void *)args->arg,
|
|
|
|
sizeof(int));
|
|
|
|
break;
|
|
|
|
}
|
2008-07-23 17:47:44 +00:00
|
|
|
case LINUX_TIOCSPTLCK:
|
|
|
|
/* Our unlockpt() does nothing. */
|
|
|
|
error = 0;
|
|
|
|
break;
|
2002-01-13 11:58:06 +00:00
|
|
|
default:
|
|
|
|
error = ENOIOCTL;
|
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
}
|
|
|
|
|
2002-01-13 11:58:06 +00:00
|
|
|
fdrop(fp, td);
|
|
|
|
return (error);
|
1996-03-03 19:07:50 +00:00
|
|
|
}
|
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
/*
|
|
|
|
* CDROM related ioctls
|
|
|
|
*/
|
|
|
|
|
1999-04-29 04:37:57 +00:00
|
|
|
struct linux_cdrom_msf
|
|
|
|
{
|
1999-12-04 11:10:22 +00:00
|
|
|
u_char cdmsf_min0;
|
|
|
|
u_char cdmsf_sec0;
|
|
|
|
u_char cdmsf_frame0;
|
|
|
|
u_char cdmsf_min1;
|
|
|
|
u_char cdmsf_sec1;
|
|
|
|
u_char cdmsf_frame1;
|
1999-04-29 04:37:57 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct linux_cdrom_tochdr
|
|
|
|
{
|
1999-12-04 11:10:22 +00:00
|
|
|
u_char cdth_trk0;
|
|
|
|
u_char cdth_trk1;
|
1999-04-29 04:37:57 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
union linux_cdrom_addr
|
|
|
|
{
|
1999-12-04 11:10:22 +00:00
|
|
|
struct {
|
|
|
|
u_char minute;
|
|
|
|
u_char second;
|
|
|
|
u_char frame;
|
|
|
|
} msf;
|
|
|
|
int lba;
|
1999-04-29 04:37:57 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct linux_cdrom_tocentry
|
|
|
|
{
|
2003-03-02 15:56:49 +00:00
|
|
|
u_char cdte_track;
|
1999-12-04 11:10:22 +00:00
|
|
|
u_char cdte_adr:4;
|
|
|
|
u_char cdte_ctrl:4;
|
2003-03-02 15:56:49 +00:00
|
|
|
u_char cdte_format;
|
1999-12-04 11:10:22 +00:00
|
|
|
union linux_cdrom_addr cdte_addr;
|
2003-03-02 15:56:49 +00:00
|
|
|
u_char cdte_datamode;
|
1999-04-29 04:37:57 +00:00
|
|
|
};
|
|
|
|
|
1999-08-13 14:44:13 +00:00
|
|
|
struct linux_cdrom_subchnl
|
|
|
|
{
|
1999-12-04 11:10:22 +00:00
|
|
|
u_char cdsc_format;
|
|
|
|
u_char cdsc_audiostatus;
|
|
|
|
u_char cdsc_adr:4;
|
|
|
|
u_char cdsc_ctrl:4;
|
|
|
|
u_char cdsc_trk;
|
|
|
|
u_char cdsc_ind;
|
|
|
|
union linux_cdrom_addr cdsc_absaddr;
|
|
|
|
union linux_cdrom_addr cdsc_reladdr;
|
1999-08-13 14:44:13 +00:00
|
|
|
};
|
|
|
|
|
2002-10-19 21:11:43 +00:00
|
|
|
struct l_cdrom_read_audio {
|
|
|
|
union linux_cdrom_addr addr;
|
|
|
|
u_char addr_format;
|
|
|
|
l_int nframes;
|
|
|
|
u_char *buf;
|
|
|
|
};
|
|
|
|
|
2001-11-18 18:49:07 +00:00
|
|
|
struct l_dvd_layer {
|
|
|
|
u_char book_version:4;
|
|
|
|
u_char book_type:4;
|
|
|
|
u_char min_rate:4;
|
|
|
|
u_char disc_size:4;
|
|
|
|
u_char layer_type:4;
|
|
|
|
u_char track_path:1;
|
|
|
|
u_char nlayers:2;
|
|
|
|
u_char track_density:4;
|
|
|
|
u_char linear_density:4;
|
|
|
|
u_char bca:1;
|
|
|
|
u_int32_t start_sector;
|
|
|
|
u_int32_t end_sector;
|
|
|
|
u_int32_t end_sector_l0;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct l_dvd_physical {
|
|
|
|
u_char type;
|
|
|
|
u_char layer_num;
|
|
|
|
struct l_dvd_layer layer[4];
|
|
|
|
};
|
|
|
|
|
|
|
|
struct l_dvd_copyright {
|
|
|
|
u_char type;
|
|
|
|
u_char layer_num;
|
|
|
|
u_char cpst;
|
|
|
|
u_char rmi;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct l_dvd_disckey {
|
|
|
|
u_char type;
|
|
|
|
l_uint agid:2;
|
|
|
|
u_char value[2048];
|
|
|
|
};
|
|
|
|
|
|
|
|
struct l_dvd_bca {
|
|
|
|
u_char type;
|
|
|
|
l_int len;
|
|
|
|
u_char value[188];
|
|
|
|
};
|
|
|
|
|
|
|
|
struct l_dvd_manufact {
|
|
|
|
u_char type;
|
|
|
|
u_char layer_num;
|
|
|
|
l_int len;
|
|
|
|
u_char value[2048];
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef union {
|
|
|
|
u_char type;
|
|
|
|
struct l_dvd_physical physical;
|
|
|
|
struct l_dvd_copyright copyright;
|
|
|
|
struct l_dvd_disckey disckey;
|
|
|
|
struct l_dvd_bca bca;
|
|
|
|
struct l_dvd_manufact manufact;
|
|
|
|
} l_dvd_struct;
|
|
|
|
|
|
|
|
typedef u_char l_dvd_key[5];
|
|
|
|
typedef u_char l_dvd_challenge[10];
|
|
|
|
|
|
|
|
struct l_dvd_lu_send_agid {
|
|
|
|
u_char type;
|
|
|
|
l_uint agid:2;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct l_dvd_host_send_challenge {
|
|
|
|
u_char type;
|
|
|
|
l_uint agid:2;
|
|
|
|
l_dvd_challenge chal;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct l_dvd_send_key {
|
|
|
|
u_char type;
|
|
|
|
l_uint agid:2;
|
|
|
|
l_dvd_key key;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct l_dvd_lu_send_challenge {
|
|
|
|
u_char type;
|
|
|
|
l_uint agid:2;
|
|
|
|
l_dvd_challenge chal;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct l_dvd_lu_send_title_key {
|
|
|
|
u_char type;
|
|
|
|
l_uint agid:2;
|
|
|
|
l_dvd_key title_key;
|
|
|
|
l_int lba;
|
|
|
|
l_uint cpm:1;
|
|
|
|
l_uint cp_sec:1;
|
|
|
|
l_uint cgms:2;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct l_dvd_lu_send_asf {
|
|
|
|
u_char type;
|
|
|
|
l_uint agid:2;
|
|
|
|
l_uint asf:1;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct l_dvd_host_send_rpcstate {
|
|
|
|
u_char type;
|
|
|
|
u_char pdrc;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct l_dvd_lu_send_rpcstate {
|
|
|
|
u_char type:2;
|
|
|
|
u_char vra:3;
|
|
|
|
u_char ucca:3;
|
|
|
|
u_char region_mask;
|
|
|
|
u_char rpc_scheme;
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef union {
|
|
|
|
u_char type;
|
|
|
|
struct l_dvd_lu_send_agid lsa;
|
|
|
|
struct l_dvd_host_send_challenge hsc;
|
|
|
|
struct l_dvd_send_key lsk;
|
|
|
|
struct l_dvd_lu_send_challenge lsc;
|
|
|
|
struct l_dvd_send_key hsk;
|
|
|
|
struct l_dvd_lu_send_title_key lstk;
|
|
|
|
struct l_dvd_lu_send_asf lsasf;
|
|
|
|
struct l_dvd_host_send_rpcstate hrpcs;
|
|
|
|
struct l_dvd_lu_send_rpcstate lrpcs;
|
|
|
|
} l_dvd_authinfo;
|
|
|
|
|
1999-04-29 04:37:57 +00:00
|
|
|
static void
|
1999-12-04 11:10:22 +00:00
|
|
|
bsd_to_linux_msf_lba(u_char af, union msf_lba *bp, union linux_cdrom_addr *lp)
|
1999-04-29 04:37:57 +00:00
|
|
|
{
|
1999-12-04 11:10:22 +00:00
|
|
|
if (af == CD_LBA_FORMAT)
|
|
|
|
lp->lba = bp->lba;
|
|
|
|
else {
|
|
|
|
lp->msf.minute = bp->msf.minute;
|
|
|
|
lp->msf.second = bp->msf.second;
|
|
|
|
lp->msf.frame = bp->msf.frame;
|
|
|
|
}
|
1999-04-29 04:37:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
1999-12-04 11:10:22 +00:00
|
|
|
set_linux_cdrom_addr(union linux_cdrom_addr *addr, int format, int lba)
|
1999-04-29 04:37:57 +00:00
|
|
|
{
|
1999-12-04 11:10:22 +00:00
|
|
|
if (format == LINUX_CDROM_MSF) {
|
|
|
|
addr->msf.frame = lba % 75;
|
|
|
|
lba /= 75;
|
|
|
|
lba += 2;
|
|
|
|
addr->msf.second = lba % 60;
|
|
|
|
addr->msf.minute = lba / 60;
|
|
|
|
} else
|
|
|
|
addr->lba = lba;
|
1999-04-29 04:37:57 +00:00
|
|
|
}
|
|
|
|
|
2001-11-18 18:49:07 +00:00
|
|
|
static int
|
|
|
|
linux_to_bsd_dvd_struct(l_dvd_struct *lp, struct dvd_struct *bp)
|
|
|
|
{
|
|
|
|
bp->format = lp->type;
|
|
|
|
switch (bp->format) {
|
|
|
|
case DVD_STRUCT_PHYSICAL:
|
|
|
|
if (bp->layer_num >= 4)
|
|
|
|
return (EINVAL);
|
|
|
|
bp->layer_num = lp->physical.layer_num;
|
|
|
|
break;
|
|
|
|
case DVD_STRUCT_COPYRIGHT:
|
|
|
|
bp->layer_num = lp->copyright.layer_num;
|
|
|
|
break;
|
|
|
|
case DVD_STRUCT_DISCKEY:
|
|
|
|
bp->agid = lp->disckey.agid;
|
|
|
|
break;
|
|
|
|
case DVD_STRUCT_BCA:
|
|
|
|
case DVD_STRUCT_MANUFACT:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return (EINVAL);
|
|
|
|
}
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
bsd_to_linux_dvd_struct(struct dvd_struct *bp, l_dvd_struct *lp)
|
|
|
|
{
|
|
|
|
switch (bp->format) {
|
|
|
|
case DVD_STRUCT_PHYSICAL: {
|
|
|
|
struct dvd_layer *blp = (struct dvd_layer *)bp->data;
|
|
|
|
struct l_dvd_layer *llp = &lp->physical.layer[bp->layer_num];
|
|
|
|
memset(llp, 0, sizeof(*llp));
|
|
|
|
llp->book_version = blp->book_version;
|
|
|
|
llp->book_type = blp->book_type;
|
|
|
|
llp->min_rate = blp->max_rate;
|
|
|
|
llp->disc_size = blp->disc_size;
|
|
|
|
llp->layer_type = blp->layer_type;
|
|
|
|
llp->track_path = blp->track_path;
|
|
|
|
llp->nlayers = blp->nlayers;
|
|
|
|
llp->track_density = blp->track_density;
|
|
|
|
llp->linear_density = blp->linear_density;
|
|
|
|
llp->bca = blp->bca;
|
|
|
|
llp->start_sector = blp->start_sector;
|
|
|
|
llp->end_sector = blp->end_sector;
|
|
|
|
llp->end_sector_l0 = blp->end_sector_l0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case DVD_STRUCT_COPYRIGHT:
|
|
|
|
lp->copyright.cpst = bp->cpst;
|
|
|
|
lp->copyright.rmi = bp->rmi;
|
|
|
|
break;
|
|
|
|
case DVD_STRUCT_DISCKEY:
|
|
|
|
memcpy(lp->disckey.value, bp->data, sizeof(lp->disckey.value));
|
|
|
|
break;
|
|
|
|
case DVD_STRUCT_BCA:
|
|
|
|
lp->bca.len = bp->length;
|
|
|
|
memcpy(lp->bca.value, bp->data, sizeof(lp->bca.value));
|
|
|
|
break;
|
|
|
|
case DVD_STRUCT_MANUFACT:
|
|
|
|
lp->manufact.len = bp->length;
|
|
|
|
memcpy(lp->manufact.value, bp->data,
|
|
|
|
sizeof(lp->manufact.value));
|
2018-02-22 02:24:17 +00:00
|
|
|
/* lp->manufact.layer_num is unused in Linux (redhat 7.0). */
|
2001-11-18 18:49:07 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return (EINVAL);
|
|
|
|
}
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
linux_to_bsd_dvd_authinfo(l_dvd_authinfo *lp, int *bcode,
|
|
|
|
struct dvd_authinfo *bp)
|
|
|
|
{
|
|
|
|
switch (lp->type) {
|
|
|
|
case LINUX_DVD_LU_SEND_AGID:
|
|
|
|
*bcode = DVDIOCREPORTKEY;
|
|
|
|
bp->format = DVD_REPORT_AGID;
|
|
|
|
bp->agid = lp->lsa.agid;
|
|
|
|
break;
|
|
|
|
case LINUX_DVD_HOST_SEND_CHALLENGE:
|
|
|
|
*bcode = DVDIOCSENDKEY;
|
|
|
|
bp->format = DVD_SEND_CHALLENGE;
|
|
|
|
bp->agid = lp->hsc.agid;
|
|
|
|
memcpy(bp->keychal, lp->hsc.chal, 10);
|
|
|
|
break;
|
|
|
|
case LINUX_DVD_LU_SEND_KEY1:
|
|
|
|
*bcode = DVDIOCREPORTKEY;
|
|
|
|
bp->format = DVD_REPORT_KEY1;
|
|
|
|
bp->agid = lp->lsk.agid;
|
|
|
|
break;
|
|
|
|
case LINUX_DVD_LU_SEND_CHALLENGE:
|
|
|
|
*bcode = DVDIOCREPORTKEY;
|
|
|
|
bp->format = DVD_REPORT_CHALLENGE;
|
|
|
|
bp->agid = lp->lsc.agid;
|
|
|
|
break;
|
|
|
|
case LINUX_DVD_HOST_SEND_KEY2:
|
|
|
|
*bcode = DVDIOCSENDKEY;
|
|
|
|
bp->format = DVD_SEND_KEY2;
|
|
|
|
bp->agid = lp->hsk.agid;
|
|
|
|
memcpy(bp->keychal, lp->hsk.key, 5);
|
|
|
|
break;
|
|
|
|
case LINUX_DVD_LU_SEND_TITLE_KEY:
|
|
|
|
*bcode = DVDIOCREPORTKEY;
|
|
|
|
bp->format = DVD_REPORT_TITLE_KEY;
|
|
|
|
bp->agid = lp->lstk.agid;
|
|
|
|
bp->lba = lp->lstk.lba;
|
|
|
|
break;
|
|
|
|
case LINUX_DVD_LU_SEND_ASF:
|
|
|
|
*bcode = DVDIOCREPORTKEY;
|
|
|
|
bp->format = DVD_REPORT_ASF;
|
|
|
|
bp->agid = lp->lsasf.agid;
|
|
|
|
break;
|
|
|
|
case LINUX_DVD_INVALIDATE_AGID:
|
|
|
|
*bcode = DVDIOCREPORTKEY;
|
|
|
|
bp->format = DVD_INVALIDATE_AGID;
|
|
|
|
bp->agid = lp->lsa.agid;
|
|
|
|
break;
|
|
|
|
case LINUX_DVD_LU_SEND_RPC_STATE:
|
|
|
|
*bcode = DVDIOCREPORTKEY;
|
|
|
|
bp->format = DVD_REPORT_RPC;
|
|
|
|
break;
|
|
|
|
case LINUX_DVD_HOST_SEND_RPC_STATE:
|
|
|
|
*bcode = DVDIOCSENDKEY;
|
|
|
|
bp->format = DVD_SEND_RPC;
|
|
|
|
bp->region = lp->hrpcs.pdrc;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return (EINVAL);
|
|
|
|
}
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
bsd_to_linux_dvd_authinfo(struct dvd_authinfo *bp, l_dvd_authinfo *lp)
|
|
|
|
{
|
|
|
|
switch (lp->type) {
|
|
|
|
case LINUX_DVD_LU_SEND_AGID:
|
|
|
|
lp->lsa.agid = bp->agid;
|
|
|
|
break;
|
|
|
|
case LINUX_DVD_HOST_SEND_CHALLENGE:
|
|
|
|
lp->type = LINUX_DVD_LU_SEND_KEY1;
|
|
|
|
break;
|
|
|
|
case LINUX_DVD_LU_SEND_KEY1:
|
|
|
|
memcpy(lp->lsk.key, bp->keychal, sizeof(lp->lsk.key));
|
|
|
|
break;
|
|
|
|
case LINUX_DVD_LU_SEND_CHALLENGE:
|
|
|
|
memcpy(lp->lsc.chal, bp->keychal, sizeof(lp->lsc.chal));
|
|
|
|
break;
|
|
|
|
case LINUX_DVD_HOST_SEND_KEY2:
|
|
|
|
lp->type = LINUX_DVD_AUTH_ESTABLISHED;
|
|
|
|
break;
|
|
|
|
case LINUX_DVD_LU_SEND_TITLE_KEY:
|
|
|
|
memcpy(lp->lstk.title_key, bp->keychal,
|
|
|
|
sizeof(lp->lstk.title_key));
|
|
|
|
lp->lstk.cpm = bp->cpm;
|
|
|
|
lp->lstk.cp_sec = bp->cp_sec;
|
|
|
|
lp->lstk.cgms = bp->cgms;
|
|
|
|
break;
|
|
|
|
case LINUX_DVD_LU_SEND_ASF:
|
|
|
|
lp->lsasf.asf = bp->asf;
|
|
|
|
break;
|
|
|
|
case LINUX_DVD_INVALIDATE_AGID:
|
|
|
|
break;
|
|
|
|
case LINUX_DVD_LU_SEND_RPC_STATE:
|
|
|
|
lp->lrpcs.type = bp->reg_type;
|
|
|
|
lp->lrpcs.vra = bp->vend_rsts;
|
|
|
|
lp->lrpcs.ucca = bp->user_rsts;
|
|
|
|
lp->lrpcs.region_mask = bp->region;
|
|
|
|
lp->lrpcs.rpc_scheme = bp->rpc_scheme;
|
|
|
|
break;
|
|
|
|
case LINUX_DVD_HOST_SEND_RPC_STATE:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return (EINVAL);
|
|
|
|
}
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
static int
|
2001-09-12 08:38:13 +00:00
|
|
|
linux_ioctl_cdrom(struct thread *td, struct linux_ioctl_args *args)
|
1999-08-13 14:44:13 +00:00
|
|
|
{
|
Change the cap_rights_t type from uint64_t to a structure that we can extend
in the future in a backward compatible (API and ABI) way.
The cap_rights_t represents capability rights. We used to use one bit to
represent one right, but we are running out of spare bits. Currently the new
structure provides place for 114 rights (so 50 more than the previous
cap_rights_t), but it is possible to grow the structure to hold at least 285
rights, although we can make it even larger if 285 rights won't be enough.
The structure definition looks like this:
struct cap_rights {
uint64_t cr_rights[CAP_RIGHTS_VERSION + 2];
};
The initial CAP_RIGHTS_VERSION is 0.
The top two bits in the first element of the cr_rights[] array contain total
number of elements in the array - 2. This means if those two bits are equal to
0, we have 2 array elements.
The top two bits in all remaining array elements should be 0.
The next five bits in all array elements contain array index. Only one bit is
used and bit position in this five-bits range defines array index. This means
there can be at most five array elements in the future.
To define new right the CAPRIGHT() macro must be used. The macro takes two
arguments - an array index and a bit to set, eg.
#define CAP_PDKILL CAPRIGHT(1, 0x0000000000000800ULL)
We still support aliases that combine few rights, but the rights have to belong
to the same array element, eg:
#define CAP_LOOKUP CAPRIGHT(0, 0x0000000000000400ULL)
#define CAP_FCHMOD CAPRIGHT(0, 0x0000000000002000ULL)
#define CAP_FCHMODAT (CAP_FCHMOD | CAP_LOOKUP)
There is new API to manage the new cap_rights_t structure:
cap_rights_t *cap_rights_init(cap_rights_t *rights, ...);
void cap_rights_set(cap_rights_t *rights, ...);
void cap_rights_clear(cap_rights_t *rights, ...);
bool cap_rights_is_set(const cap_rights_t *rights, ...);
bool cap_rights_is_valid(const cap_rights_t *rights);
void cap_rights_merge(cap_rights_t *dst, const cap_rights_t *src);
void cap_rights_remove(cap_rights_t *dst, const cap_rights_t *src);
bool cap_rights_contains(const cap_rights_t *big, const cap_rights_t *little);
Capability rights to the cap_rights_init(), cap_rights_set(),
cap_rights_clear() and cap_rights_is_set() functions are provided by
separating them with commas, eg:
cap_rights_t rights;
cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_FSTAT);
There is no need to terminate the list of rights, as those functions are
actually macros that take care of the termination, eg:
#define cap_rights_set(rights, ...) \
__cap_rights_set((rights), __VA_ARGS__, 0ULL)
void __cap_rights_set(cap_rights_t *rights, ...);
Thanks to using one bit as an array index we can assert in those functions that
there are no two rights belonging to different array elements provided
together. For example this is illegal and will be detected, because CAP_LOOKUP
belongs to element 0 and CAP_PDKILL to element 1:
cap_rights_init(&rights, CAP_LOOKUP | CAP_PDKILL);
Providing several rights that belongs to the same array's element this way is
correct, but is not advised. It should only be used for aliases definition.
This commit also breaks compatibility with some existing Capsicum system calls,
but I see no other way to do that. This should be fine as Capsicum is still
experimental and this change is not going to 9.x.
Sponsored by: The FreeBSD Foundation
2013-09-05 00:09:56 +00:00
|
|
|
cap_rights_t rights;
|
2002-01-13 11:58:06 +00:00
|
|
|
struct file *fp;
|
1999-12-04 11:10:22 +00:00
|
|
|
int error;
|
|
|
|
|
Change the cap_rights_t type from uint64_t to a structure that we can extend
in the future in a backward compatible (API and ABI) way.
The cap_rights_t represents capability rights. We used to use one bit to
represent one right, but we are running out of spare bits. Currently the new
structure provides place for 114 rights (so 50 more than the previous
cap_rights_t), but it is possible to grow the structure to hold at least 285
rights, although we can make it even larger if 285 rights won't be enough.
The structure definition looks like this:
struct cap_rights {
uint64_t cr_rights[CAP_RIGHTS_VERSION + 2];
};
The initial CAP_RIGHTS_VERSION is 0.
The top two bits in the first element of the cr_rights[] array contain total
number of elements in the array - 2. This means if those two bits are equal to
0, we have 2 array elements.
The top two bits in all remaining array elements should be 0.
The next five bits in all array elements contain array index. Only one bit is
used and bit position in this five-bits range defines array index. This means
there can be at most five array elements in the future.
To define new right the CAPRIGHT() macro must be used. The macro takes two
arguments - an array index and a bit to set, eg.
#define CAP_PDKILL CAPRIGHT(1, 0x0000000000000800ULL)
We still support aliases that combine few rights, but the rights have to belong
to the same array element, eg:
#define CAP_LOOKUP CAPRIGHT(0, 0x0000000000000400ULL)
#define CAP_FCHMOD CAPRIGHT(0, 0x0000000000002000ULL)
#define CAP_FCHMODAT (CAP_FCHMOD | CAP_LOOKUP)
There is new API to manage the new cap_rights_t structure:
cap_rights_t *cap_rights_init(cap_rights_t *rights, ...);
void cap_rights_set(cap_rights_t *rights, ...);
void cap_rights_clear(cap_rights_t *rights, ...);
bool cap_rights_is_set(const cap_rights_t *rights, ...);
bool cap_rights_is_valid(const cap_rights_t *rights);
void cap_rights_merge(cap_rights_t *dst, const cap_rights_t *src);
void cap_rights_remove(cap_rights_t *dst, const cap_rights_t *src);
bool cap_rights_contains(const cap_rights_t *big, const cap_rights_t *little);
Capability rights to the cap_rights_init(), cap_rights_set(),
cap_rights_clear() and cap_rights_is_set() functions are provided by
separating them with commas, eg:
cap_rights_t rights;
cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_FSTAT);
There is no need to terminate the list of rights, as those functions are
actually macros that take care of the termination, eg:
#define cap_rights_set(rights, ...) \
__cap_rights_set((rights), __VA_ARGS__, 0ULL)
void __cap_rights_set(cap_rights_t *rights, ...);
Thanks to using one bit as an array index we can assert in those functions that
there are no two rights belonging to different array elements provided
together. For example this is illegal and will be detected, because CAP_LOOKUP
belongs to element 0 and CAP_PDKILL to element 1:
cap_rights_init(&rights, CAP_LOOKUP | CAP_PDKILL);
Providing several rights that belongs to the same array's element this way is
correct, but is not advised. It should only be used for aliases definition.
This commit also breaks compatibility with some existing Capsicum system calls,
but I see no other way to do that. This should be fine as Capsicum is still
experimental and this change is not going to 9.x.
Sponsored by: The FreeBSD Foundation
2013-09-05 00:09:56 +00:00
|
|
|
error = fget(td, args->fd, cap_rights_init(&rights, CAP_IOCTL), &fp);
|
|
|
|
if (error != 0)
|
2002-01-14 00:13:45 +00:00
|
|
|
return (error);
|
1999-12-04 11:10:22 +00:00
|
|
|
switch (args->cmd & 0xffff) {
|
|
|
|
|
|
|
|
case LINUX_CDROMPAUSE:
|
|
|
|
args->cmd = CDIOCPAUSE;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = (sys_ioctl(td, (struct ioctl_args *)args));
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
case LINUX_CDROMRESUME:
|
|
|
|
args->cmd = CDIOCRESUME;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = (sys_ioctl(td, (struct ioctl_args *)args));
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
case LINUX_CDROMPLAYMSF:
|
|
|
|
args->cmd = CDIOCPLAYMSF;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = (sys_ioctl(td, (struct ioctl_args *)args));
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
case LINUX_CDROMPLAYTRKIND:
|
|
|
|
args->cmd = CDIOCPLAYTRACKS;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = (sys_ioctl(td, (struct ioctl_args *)args));
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
case LINUX_CDROMREADTOCHDR: {
|
|
|
|
struct ioc_toc_header th;
|
|
|
|
struct linux_cdrom_tochdr lth;
|
2002-08-17 02:36:16 +00:00
|
|
|
error = fo_ioctl(fp, CDIOREADTOCHEADER, (caddr_t)&th,
|
|
|
|
td->td_ucred, td);
|
1999-12-04 11:10:22 +00:00
|
|
|
if (!error) {
|
|
|
|
lth.cdth_trk0 = th.starting_track;
|
|
|
|
lth.cdth_trk1 = th.ending_track;
|
2003-03-03 09:14:26 +00:00
|
|
|
copyout(<h, (void *)args->arg, sizeof(lth));
|
1999-12-04 11:10:22 +00:00
|
|
|
}
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
case LINUX_CDROMREADTOCENTRY: {
|
2004-06-18 13:36:30 +00:00
|
|
|
struct linux_cdrom_tocentry lte;
|
1999-12-04 11:10:22 +00:00
|
|
|
struct ioc_read_toc_single_entry irtse;
|
2004-06-18 13:36:30 +00:00
|
|
|
|
|
|
|
error = copyin((void *)args->arg, <e, sizeof(lte));
|
|
|
|
if (error)
|
|
|
|
break;
|
|
|
|
irtse.address_format = lte.cdte_format;
|
|
|
|
irtse.track = lte.cdte_track;
|
|
|
|
error = fo_ioctl(fp, CDIOREADTOCENTRY, (caddr_t)&irtse,
|
|
|
|
td->td_ucred, td);
|
1999-12-04 11:10:22 +00:00
|
|
|
if (!error) {
|
|
|
|
lte.cdte_ctrl = irtse.entry.control;
|
|
|
|
lte.cdte_adr = irtse.entry.addr_type;
|
|
|
|
bsd_to_linux_msf_lba(irtse.address_format,
|
|
|
|
&irtse.entry.addr, <e.cdte_addr);
|
2004-06-18 13:36:30 +00:00
|
|
|
error = copyout(<e, (void *)args->arg, sizeof(lte));
|
1999-12-04 11:10:22 +00:00
|
|
|
}
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
case LINUX_CDROMSTOP:
|
|
|
|
args->cmd = CDIOCSTOP;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = (sys_ioctl(td, (struct ioctl_args *)args));
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
case LINUX_CDROMSTART:
|
|
|
|
args->cmd = CDIOCSTART;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = (sys_ioctl(td, (struct ioctl_args *)args));
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
case LINUX_CDROMEJECT:
|
|
|
|
args->cmd = CDIOCEJECT;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = (sys_ioctl(td, (struct ioctl_args *)args));
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
/* LINUX_CDROMVOLCTRL */
|
|
|
|
|
|
|
|
case LINUX_CDROMSUBCHNL: {
|
|
|
|
struct linux_cdrom_subchnl sc;
|
|
|
|
struct ioc_read_subchannel bsdsc;
|
2005-01-30 08:12:37 +00:00
|
|
|
struct cd_sub_channel_info bsdinfo;
|
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
bsdsc.address_format = CD_LBA_FORMAT;
|
|
|
|
bsdsc.data_format = CD_CURRENT_POSITION;
|
2000-02-01 16:20:24 +00:00
|
|
|
bsdsc.track = 0;
|
2005-01-30 08:12:37 +00:00
|
|
|
bsdsc.data_len = sizeof(bsdinfo);
|
|
|
|
bsdsc.data = &bsdinfo;
|
|
|
|
error = fo_ioctl(fp, CDIOCREADSUBCHANNEL_SYSSPACE,
|
|
|
|
(caddr_t)&bsdsc, td->td_ucred, td);
|
1999-12-04 11:10:22 +00:00
|
|
|
if (error)
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
2003-03-03 09:14:26 +00:00
|
|
|
error = copyin((void *)args->arg, &sc, sizeof(sc));
|
1999-12-04 11:10:22 +00:00
|
|
|
if (error)
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
2005-01-30 08:12:37 +00:00
|
|
|
sc.cdsc_audiostatus = bsdinfo.header.audio_status;
|
|
|
|
sc.cdsc_adr = bsdinfo.what.position.addr_type;
|
|
|
|
sc.cdsc_ctrl = bsdinfo.what.position.control;
|
|
|
|
sc.cdsc_trk = bsdinfo.what.position.track_number;
|
|
|
|
sc.cdsc_ind = bsdinfo.what.position.index_number;
|
1999-12-04 11:10:22 +00:00
|
|
|
set_linux_cdrom_addr(&sc.cdsc_absaddr, sc.cdsc_format,
|
2005-01-30 08:12:37 +00:00
|
|
|
bsdinfo.what.position.absaddr.lba);
|
1999-12-04 11:10:22 +00:00
|
|
|
set_linux_cdrom_addr(&sc.cdsc_reladdr, sc.cdsc_format,
|
2005-01-30 08:12:37 +00:00
|
|
|
bsdinfo.what.position.reladdr.lba);
|
2003-03-03 09:14:26 +00:00
|
|
|
error = copyout(&sc, (void *)args->arg, sizeof(sc));
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* LINUX_CDROMREADMODE2 */
|
|
|
|
/* LINUX_CDROMREADMODE1 */
|
2003-10-20 09:51:00 +00:00
|
|
|
/* LINUX_CDROMREADAUDIO */
|
1999-12-04 11:10:22 +00:00
|
|
|
/* LINUX_CDROMEJECT_SW */
|
|
|
|
/* LINUX_CDROMMULTISESSION */
|
|
|
|
/* LINUX_CDROM_GET_UPC */
|
|
|
|
|
|
|
|
case LINUX_CDROMRESET:
|
|
|
|
args->cmd = CDIOCRESET;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = (sys_ioctl(td, (struct ioctl_args *)args));
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
/* LINUX_CDROMVOLREAD */
|
|
|
|
/* LINUX_CDROMREADRAW */
|
|
|
|
/* LINUX_CDROMREADCOOKED */
|
|
|
|
/* LINUX_CDROMSEEK */
|
|
|
|
/* LINUX_CDROMPLAYBLK */
|
|
|
|
/* LINUX_CDROMREADALL */
|
|
|
|
/* LINUX_CDROMCLOSETRAY */
|
|
|
|
/* LINUX_CDROMLOADFROMSLOT */
|
2001-11-18 18:49:07 +00:00
|
|
|
/* LINUX_CDROMGETSPINDOWN */
|
|
|
|
/* LINUX_CDROMSETSPINDOWN */
|
|
|
|
/* LINUX_CDROM_SET_OPTIONS */
|
|
|
|
/* LINUX_CDROM_CLEAR_OPTIONS */
|
|
|
|
/* LINUX_CDROM_SELECT_SPEED */
|
|
|
|
/* LINUX_CDROM_SELECT_DISC */
|
|
|
|
/* LINUX_CDROM_MEDIA_CHANGED */
|
|
|
|
/* LINUX_CDROM_DRIVE_STATUS */
|
|
|
|
/* LINUX_CDROM_DISC_STATUS */
|
|
|
|
/* LINUX_CDROM_CHANGER_NSLOTS */
|
|
|
|
/* LINUX_CDROM_LOCKDOOR */
|
|
|
|
/* LINUX_CDROM_DEBUG */
|
|
|
|
/* LINUX_CDROM_GET_CAPABILITY */
|
|
|
|
/* LINUX_CDROMAUDIOBUFSIZ */
|
|
|
|
|
|
|
|
case LINUX_DVD_READ_STRUCT: {
|
2009-05-27 15:23:12 +00:00
|
|
|
l_dvd_struct *lds;
|
|
|
|
struct dvd_struct *bds;
|
2001-11-18 18:49:07 +00:00
|
|
|
|
2009-05-27 15:23:12 +00:00
|
|
|
lds = malloc(sizeof(*lds), M_LINUX, M_WAITOK);
|
|
|
|
bds = malloc(sizeof(*bds), M_LINUX, M_WAITOK);
|
|
|
|
error = copyin((void *)args->arg, lds, sizeof(*lds));
|
2001-11-18 18:49:07 +00:00
|
|
|
if (error)
|
2009-05-27 15:23:12 +00:00
|
|
|
goto out;
|
|
|
|
error = linux_to_bsd_dvd_struct(lds, bds);
|
2001-11-18 18:49:07 +00:00
|
|
|
if (error)
|
2009-05-27 15:23:12 +00:00
|
|
|
goto out;
|
|
|
|
error = fo_ioctl(fp, DVDIOCREADSTRUCTURE, (caddr_t)bds,
|
2002-08-17 02:36:16 +00:00
|
|
|
td->td_ucred, td);
|
2001-11-18 18:49:07 +00:00
|
|
|
if (error)
|
2009-05-27 15:23:12 +00:00
|
|
|
goto out;
|
|
|
|
error = bsd_to_linux_dvd_struct(bds, lds);
|
2001-11-18 18:49:07 +00:00
|
|
|
if (error)
|
2009-05-27 15:23:12 +00:00
|
|
|
goto out;
|
|
|
|
error = copyout(lds, (void *)args->arg, sizeof(*lds));
|
|
|
|
out:
|
|
|
|
free(bds, M_LINUX);
|
|
|
|
free(lds, M_LINUX);
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
2001-11-18 18:49:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* LINUX_DVD_WRITE_STRUCT */
|
|
|
|
|
|
|
|
case LINUX_DVD_AUTH: {
|
|
|
|
l_dvd_authinfo lda;
|
|
|
|
struct dvd_authinfo bda;
|
|
|
|
int bcode;
|
|
|
|
|
2003-03-03 09:14:26 +00:00
|
|
|
error = copyin((void *)args->arg, &lda, sizeof(lda));
|
2001-11-18 18:49:07 +00:00
|
|
|
if (error)
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
2001-11-18 18:49:07 +00:00
|
|
|
error = linux_to_bsd_dvd_authinfo(&lda, &bcode, &bda);
|
|
|
|
if (error)
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
2002-08-17 02:36:16 +00:00
|
|
|
error = fo_ioctl(fp, bcode, (caddr_t)&bda, td->td_ucred,
|
|
|
|
td);
|
2001-11-18 18:49:07 +00:00
|
|
|
if (error) {
|
|
|
|
if (lda.type == LINUX_DVD_HOST_SEND_KEY2) {
|
|
|
|
lda.type = LINUX_DVD_AUTH_FAILURE;
|
2003-03-03 09:14:26 +00:00
|
|
|
copyout(&lda, (void *)args->arg, sizeof(lda));
|
2001-11-18 18:49:07 +00:00
|
|
|
}
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
2001-11-18 18:49:07 +00:00
|
|
|
}
|
|
|
|
error = bsd_to_linux_dvd_authinfo(&bda, &lda);
|
|
|
|
if (error)
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
2003-03-03 09:14:26 +00:00
|
|
|
error = copyout(&lda, (void *)args->arg, sizeof(lda));
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
2001-11-18 18:49:07 +00:00
|
|
|
}
|
|
|
|
|
2007-04-07 19:40:58 +00:00
|
|
|
case LINUX_SCSI_GET_BUS_NUMBER:
|
2014-06-02 19:53:53 +00:00
|
|
|
{
|
|
|
|
struct sg_scsi_id id;
|
|
|
|
|
|
|
|
error = fo_ioctl(fp, SG_GET_SCSI_ID, (caddr_t)&id,
|
|
|
|
td->td_ucred, td);
|
|
|
|
if (error)
|
|
|
|
break;
|
|
|
|
error = copyout(&id.channel, (void *)args->arg, sizeof(int));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2007-04-07 19:40:58 +00:00
|
|
|
case LINUX_SCSI_GET_IDLUN:
|
2014-06-02 19:53:53 +00:00
|
|
|
{
|
|
|
|
struct sg_scsi_id id;
|
|
|
|
struct scsi_idlun idl;
|
|
|
|
|
|
|
|
error = fo_ioctl(fp, SG_GET_SCSI_ID, (caddr_t)&id,
|
|
|
|
td->td_ucred, td);
|
|
|
|
if (error)
|
|
|
|
break;
|
|
|
|
idl.dev_id = (id.scsi_id & 0xff) + ((id.lun & 0xff) << 8) +
|
|
|
|
((id.channel & 0xff) << 16) + ((id.host_no & 0xff) << 24);
|
|
|
|
idl.host_unique_id = id.host_no;
|
|
|
|
error = copyout(&idl, (void *)args->arg, sizeof(idl));
|
2007-04-07 19:40:58 +00:00
|
|
|
break;
|
2014-06-02 19:53:53 +00:00
|
|
|
}
|
2007-04-07 19:40:58 +00:00
|
|
|
|
2001-11-18 18:49:07 +00:00
|
|
|
/* LINUX_CDROM_SEND_PACKET */
|
|
|
|
/* LINUX_CDROM_NEXT_WRITABLE */
|
|
|
|
/* LINUX_CDROM_LAST_WRITTEN */
|
1999-12-04 11:10:22 +00:00
|
|
|
|
2002-01-13 11:58:06 +00:00
|
|
|
default:
|
|
|
|
error = ENOIOCTL;
|
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
}
|
|
|
|
|
2002-01-13 11:58:06 +00:00
|
|
|
fdrop(fp, td);
|
|
|
|
return (error);
|
1999-08-13 14:44:13 +00:00
|
|
|
}
|
|
|
|
|
2002-10-11 11:43:09 +00:00
|
|
|
static int
|
|
|
|
linux_ioctl_vfat(struct thread *td, struct linux_ioctl_args *args)
|
|
|
|
{
|
|
|
|
|
|
|
|
return (ENOTTY);
|
|
|
|
}
|
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
/*
|
|
|
|
* Sound related ioctls
|
|
|
|
*/
|
|
|
|
|
2005-04-13 04:33:06 +00:00
|
|
|
struct linux_old_mixer_info {
|
|
|
|
char id[16];
|
|
|
|
char name[32];
|
|
|
|
};
|
|
|
|
|
2000-11-01 19:48:35 +00:00
|
|
|
static u_int32_t dirbits[4] = { IOC_VOID, IOC_IN, IOC_OUT, IOC_INOUT };
|
1999-04-29 04:37:57 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
#define SETDIR(c) (((c) & ~IOC_DIRMASK) | dirbits[args->cmd >> 30])
|
1999-04-29 04:37:57 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
static int
|
2001-09-12 08:38:13 +00:00
|
|
|
linux_ioctl_sound(struct thread *td, struct linux_ioctl_args *args)
|
1995-06-25 17:32:43 +00:00
|
|
|
{
|
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
switch (args->cmd & 0xffff) {
|
1997-06-02 06:31:49 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
case LINUX_SOUND_MIXER_WRITE_VOLUME:
|
|
|
|
args->cmd = SETDIR(SOUND_MIXER_WRITE_VOLUME);
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
1997-06-02 06:31:49 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
case LINUX_SOUND_MIXER_WRITE_BASS:
|
|
|
|
args->cmd = SETDIR(SOUND_MIXER_WRITE_BASS);
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
1997-06-02 06:31:49 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
case LINUX_SOUND_MIXER_WRITE_TREBLE:
|
|
|
|
args->cmd = SETDIR(SOUND_MIXER_WRITE_TREBLE);
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
case LINUX_SOUND_MIXER_WRITE_SYNTH:
|
|
|
|
args->cmd = SETDIR(SOUND_MIXER_WRITE_SYNTH);
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
case LINUX_SOUND_MIXER_WRITE_PCM:
|
|
|
|
args->cmd = SETDIR(SOUND_MIXER_WRITE_PCM);
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
case LINUX_SOUND_MIXER_WRITE_SPEAKER:
|
|
|
|
args->cmd = SETDIR(SOUND_MIXER_WRITE_SPEAKER);
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
case LINUX_SOUND_MIXER_WRITE_LINE:
|
|
|
|
args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE);
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
case LINUX_SOUND_MIXER_WRITE_MIC:
|
|
|
|
args->cmd = SETDIR(SOUND_MIXER_WRITE_MIC);
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
1995-06-25 17:32:43 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
case LINUX_SOUND_MIXER_WRITE_CD:
|
|
|
|
args->cmd = SETDIR(SOUND_MIXER_WRITE_CD);
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
case LINUX_SOUND_MIXER_WRITE_IMIX:
|
|
|
|
args->cmd = SETDIR(SOUND_MIXER_WRITE_IMIX);
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
case LINUX_SOUND_MIXER_WRITE_ALTPCM:
|
|
|
|
args->cmd = SETDIR(SOUND_MIXER_WRITE_ALTPCM);
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
case LINUX_SOUND_MIXER_WRITE_RECLEV:
|
|
|
|
args->cmd = SETDIR(SOUND_MIXER_WRITE_RECLEV);
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
case LINUX_SOUND_MIXER_WRITE_IGAIN:
|
|
|
|
args->cmd = SETDIR(SOUND_MIXER_WRITE_IGAIN);
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
case LINUX_SOUND_MIXER_WRITE_OGAIN:
|
|
|
|
args->cmd = SETDIR(SOUND_MIXER_WRITE_OGAIN);
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
case LINUX_SOUND_MIXER_WRITE_LINE1:
|
|
|
|
args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE1);
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
case LINUX_SOUND_MIXER_WRITE_LINE2:
|
|
|
|
args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE2);
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
case LINUX_SOUND_MIXER_WRITE_LINE3:
|
|
|
|
args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE3);
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
1999-12-04 11:10:22 +00:00
|
|
|
|
2005-04-13 04:33:06 +00:00
|
|
|
case LINUX_SOUND_MIXER_INFO: {
|
|
|
|
/* Key on encoded length */
|
|
|
|
switch ((args->cmd >> 16) & 0x1fff) {
|
|
|
|
case 0x005c: { /* SOUND_MIXER_INFO */
|
2014-09-24 08:18:11 +00:00
|
|
|
args->cmd = SOUND_MIXER_INFO;
|
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
2005-04-13 04:33:06 +00:00
|
|
|
}
|
|
|
|
case 0x0030: { /* SOUND_OLD_MIXER_INFO */
|
|
|
|
struct linux_old_mixer_info info;
|
|
|
|
bzero(&info, sizeof(info));
|
|
|
|
strncpy(info.id, "OSS", sizeof(info.id) - 1);
|
|
|
|
strncpy(info.name, "FreeBSD OSS Mixer", sizeof(info.name) - 1);
|
|
|
|
copyout(&info, (void *)args->arg, sizeof(info));
|
2010-12-30 02:18:04 +00:00
|
|
|
return (0);
|
2005-04-13 04:33:06 +00:00
|
|
|
}
|
|
|
|
default:
|
|
|
|
return (ENOIOCTL);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2004-06-18 14:25:44 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
case LINUX_OSS_GETVERSION: {
|
2003-03-13 22:45:43 +00:00
|
|
|
int version = linux_get_oss_version(td);
|
2003-03-03 09:14:26 +00:00
|
|
|
return (copyout(&version, (void *)args->arg, sizeof(int)));
|
1995-06-25 17:32:43 +00:00
|
|
|
}
|
1995-12-29 22:12:14 +00:00
|
|
|
|
2002-10-11 11:43:09 +00:00
|
|
|
case LINUX_SOUND_MIXER_READ_STEREODEVS:
|
|
|
|
args->cmd = SOUND_MIXER_READ_STEREODEVS;
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
2002-10-11 11:43:09 +00:00
|
|
|
|
2010-12-30 02:18:04 +00:00
|
|
|
case LINUX_SOUND_MIXER_READ_CAPS:
|
|
|
|
args->cmd = SOUND_MIXER_READ_CAPS;
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
2010-12-30 02:18:04 +00:00
|
|
|
|
2004-06-18 14:36:24 +00:00
|
|
|
case LINUX_SOUND_MIXER_READ_RECMASK:
|
|
|
|
args->cmd = SOUND_MIXER_READ_RECMASK;
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
2004-06-18 14:36:24 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
case LINUX_SOUND_MIXER_READ_DEVMASK:
|
|
|
|
args->cmd = SOUND_MIXER_READ_DEVMASK;
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
1998-11-12 00:42:08 +00:00
|
|
|
|
2001-11-18 06:36:18 +00:00
|
|
|
case LINUX_SOUND_MIXER_WRITE_RECSRC:
|
|
|
|
args->cmd = SETDIR(SOUND_MIXER_WRITE_RECSRC);
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
2001-11-18 06:36:18 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
case LINUX_SNDCTL_DSP_RESET:
|
|
|
|
args->cmd = SNDCTL_DSP_RESET;
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
1998-11-12 00:42:08 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
case LINUX_SNDCTL_DSP_SYNC:
|
|
|
|
args->cmd = SNDCTL_DSP_SYNC;
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
1998-11-12 00:42:08 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
case LINUX_SNDCTL_DSP_SPEED:
|
|
|
|
args->cmd = SNDCTL_DSP_SPEED;
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
1998-11-12 00:42:08 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
case LINUX_SNDCTL_DSP_STEREO:
|
|
|
|
args->cmd = SNDCTL_DSP_STEREO;
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
1998-11-12 00:42:08 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
case LINUX_SNDCTL_DSP_GETBLKSIZE: /* LINUX_SNDCTL_DSP_SETBLKSIZE */
|
|
|
|
args->cmd = SNDCTL_DSP_GETBLKSIZE;
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
1998-11-12 00:42:08 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
case LINUX_SNDCTL_DSP_SETFMT:
|
|
|
|
args->cmd = SNDCTL_DSP_SETFMT;
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
1998-11-12 00:42:08 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
case LINUX_SOUND_PCM_WRITE_CHANNELS:
|
|
|
|
args->cmd = SOUND_PCM_WRITE_CHANNELS;
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
1998-11-12 00:42:08 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
case LINUX_SOUND_PCM_WRITE_FILTER:
|
|
|
|
args->cmd = SOUND_PCM_WRITE_FILTER;
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
1998-11-12 00:42:08 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
case LINUX_SNDCTL_DSP_POST:
|
|
|
|
args->cmd = SNDCTL_DSP_POST;
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
1998-11-12 00:42:08 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
case LINUX_SNDCTL_DSP_SUBDIVIDE:
|
|
|
|
args->cmd = SNDCTL_DSP_SUBDIVIDE;
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
1998-11-12 00:42:08 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
case LINUX_SNDCTL_DSP_SETFRAGMENT:
|
|
|
|
args->cmd = SNDCTL_DSP_SETFRAGMENT;
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
1998-11-12 00:42:08 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
case LINUX_SNDCTL_DSP_GETFMTS:
|
|
|
|
args->cmd = SNDCTL_DSP_GETFMTS;
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
1998-11-12 00:42:08 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
case LINUX_SNDCTL_DSP_GETOSPACE:
|
|
|
|
args->cmd = SNDCTL_DSP_GETOSPACE;
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
1998-11-12 00:42:08 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
case LINUX_SNDCTL_DSP_GETISPACE:
|
|
|
|
args->cmd = SNDCTL_DSP_GETISPACE;
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
1998-11-12 00:42:08 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
case LINUX_SNDCTL_DSP_NONBLOCK:
|
|
|
|
args->cmd = SNDCTL_DSP_NONBLOCK;
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
1997-11-17 04:00:32 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
case LINUX_SNDCTL_DSP_GETCAPS:
|
|
|
|
args->cmd = SNDCTL_DSP_GETCAPS;
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
1997-11-17 04:00:32 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
case LINUX_SNDCTL_DSP_SETTRIGGER: /* LINUX_SNDCTL_GETTRIGGER */
|
|
|
|
args->cmd = SNDCTL_DSP_SETTRIGGER;
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
1997-11-17 04:00:32 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
case LINUX_SNDCTL_DSP_GETIPTR:
|
|
|
|
args->cmd = SNDCTL_DSP_GETIPTR;
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
1997-11-17 04:00:32 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
case LINUX_SNDCTL_DSP_GETOPTR:
|
|
|
|
args->cmd = SNDCTL_DSP_GETOPTR;
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
1995-12-29 22:12:14 +00:00
|
|
|
|
2004-07-02 15:31:44 +00:00
|
|
|
case LINUX_SNDCTL_DSP_SETDUPLEX:
|
|
|
|
args->cmd = SNDCTL_DSP_SETDUPLEX;
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
2004-07-02 15:31:44 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
case LINUX_SNDCTL_DSP_GETODELAY:
|
|
|
|
args->cmd = SNDCTL_DSP_GETODELAY;
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
1995-12-29 22:12:14 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
case LINUX_SNDCTL_SEQ_RESET:
|
|
|
|
args->cmd = SNDCTL_SEQ_RESET;
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
1995-12-29 22:12:14 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
case LINUX_SNDCTL_SEQ_SYNC:
|
|
|
|
args->cmd = SNDCTL_SEQ_SYNC;
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
1995-12-29 22:12:14 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
case LINUX_SNDCTL_SYNTH_INFO:
|
|
|
|
args->cmd = SNDCTL_SYNTH_INFO;
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
1995-12-29 22:12:14 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
case LINUX_SNDCTL_SEQ_CTRLRATE:
|
|
|
|
args->cmd = SNDCTL_SEQ_CTRLRATE;
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
1999-11-29 23:03:34 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
case LINUX_SNDCTL_SEQ_GETOUTCOUNT:
|
|
|
|
args->cmd = SNDCTL_SEQ_GETOUTCOUNT;
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
1995-12-29 22:12:14 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
case LINUX_SNDCTL_SEQ_GETINCOUNT:
|
|
|
|
args->cmd = SNDCTL_SEQ_GETINCOUNT;
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
1995-12-29 22:12:14 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
case LINUX_SNDCTL_SEQ_PERCMODE:
|
|
|
|
args->cmd = SNDCTL_SEQ_PERCMODE;
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
1995-12-29 22:12:14 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
case LINUX_SNDCTL_FM_LOAD_INSTR:
|
|
|
|
args->cmd = SNDCTL_FM_LOAD_INSTR;
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
1995-12-29 22:12:14 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
case LINUX_SNDCTL_SEQ_TESTMIDI:
|
|
|
|
args->cmd = SNDCTL_SEQ_TESTMIDI;
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
1995-12-29 22:12:14 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
case LINUX_SNDCTL_SEQ_RESETSAMPLES:
|
|
|
|
args->cmd = SNDCTL_SEQ_RESETSAMPLES;
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
1996-11-05 02:04:37 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
case LINUX_SNDCTL_SEQ_NRSYNTHS:
|
|
|
|
args->cmd = SNDCTL_SEQ_NRSYNTHS;
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
1996-11-05 02:04:37 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
case LINUX_SNDCTL_SEQ_NRMIDIS:
|
|
|
|
args->cmd = SNDCTL_SEQ_NRMIDIS;
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
1996-11-05 02:04:37 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
case LINUX_SNDCTL_MIDI_INFO:
|
|
|
|
args->cmd = SNDCTL_MIDI_INFO;
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
1996-11-05 02:04:37 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
case LINUX_SNDCTL_SEQ_TRESHOLD:
|
|
|
|
args->cmd = SNDCTL_SEQ_TRESHOLD;
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
1996-11-05 02:04:37 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
case LINUX_SNDCTL_SYNTH_MEMAVL:
|
|
|
|
args->cmd = SNDCTL_SYNTH_MEMAVL;
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
1999-08-14 13:26:44 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
}
|
1999-08-14 13:26:44 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
return (ENOIOCTL);
|
|
|
|
}
|
1996-03-10 22:30:53 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
/*
|
|
|
|
* Console related ioctls
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int
|
2001-09-12 08:38:13 +00:00
|
|
|
linux_ioctl_console(struct thread *td, struct linux_ioctl_args *args)
|
1999-12-04 11:10:22 +00:00
|
|
|
{
|
Change the cap_rights_t type from uint64_t to a structure that we can extend
in the future in a backward compatible (API and ABI) way.
The cap_rights_t represents capability rights. We used to use one bit to
represent one right, but we are running out of spare bits. Currently the new
structure provides place for 114 rights (so 50 more than the previous
cap_rights_t), but it is possible to grow the structure to hold at least 285
rights, although we can make it even larger if 285 rights won't be enough.
The structure definition looks like this:
struct cap_rights {
uint64_t cr_rights[CAP_RIGHTS_VERSION + 2];
};
The initial CAP_RIGHTS_VERSION is 0.
The top two bits in the first element of the cr_rights[] array contain total
number of elements in the array - 2. This means if those two bits are equal to
0, we have 2 array elements.
The top two bits in all remaining array elements should be 0.
The next five bits in all array elements contain array index. Only one bit is
used and bit position in this five-bits range defines array index. This means
there can be at most five array elements in the future.
To define new right the CAPRIGHT() macro must be used. The macro takes two
arguments - an array index and a bit to set, eg.
#define CAP_PDKILL CAPRIGHT(1, 0x0000000000000800ULL)
We still support aliases that combine few rights, but the rights have to belong
to the same array element, eg:
#define CAP_LOOKUP CAPRIGHT(0, 0x0000000000000400ULL)
#define CAP_FCHMOD CAPRIGHT(0, 0x0000000000002000ULL)
#define CAP_FCHMODAT (CAP_FCHMOD | CAP_LOOKUP)
There is new API to manage the new cap_rights_t structure:
cap_rights_t *cap_rights_init(cap_rights_t *rights, ...);
void cap_rights_set(cap_rights_t *rights, ...);
void cap_rights_clear(cap_rights_t *rights, ...);
bool cap_rights_is_set(const cap_rights_t *rights, ...);
bool cap_rights_is_valid(const cap_rights_t *rights);
void cap_rights_merge(cap_rights_t *dst, const cap_rights_t *src);
void cap_rights_remove(cap_rights_t *dst, const cap_rights_t *src);
bool cap_rights_contains(const cap_rights_t *big, const cap_rights_t *little);
Capability rights to the cap_rights_init(), cap_rights_set(),
cap_rights_clear() and cap_rights_is_set() functions are provided by
separating them with commas, eg:
cap_rights_t rights;
cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_FSTAT);
There is no need to terminate the list of rights, as those functions are
actually macros that take care of the termination, eg:
#define cap_rights_set(rights, ...) \
__cap_rights_set((rights), __VA_ARGS__, 0ULL)
void __cap_rights_set(cap_rights_t *rights, ...);
Thanks to using one bit as an array index we can assert in those functions that
there are no two rights belonging to different array elements provided
together. For example this is illegal and will be detected, because CAP_LOOKUP
belongs to element 0 and CAP_PDKILL to element 1:
cap_rights_init(&rights, CAP_LOOKUP | CAP_PDKILL);
Providing several rights that belongs to the same array's element this way is
correct, but is not advised. It should only be used for aliases definition.
This commit also breaks compatibility with some existing Capsicum system calls,
but I see no other way to do that. This should be fine as Capsicum is still
experimental and this change is not going to 9.x.
Sponsored by: The FreeBSD Foundation
2013-09-05 00:09:56 +00:00
|
|
|
cap_rights_t rights;
|
2002-01-13 11:58:06 +00:00
|
|
|
struct file *fp;
|
|
|
|
int error;
|
1999-12-04 11:10:22 +00:00
|
|
|
|
Change the cap_rights_t type from uint64_t to a structure that we can extend
in the future in a backward compatible (API and ABI) way.
The cap_rights_t represents capability rights. We used to use one bit to
represent one right, but we are running out of spare bits. Currently the new
structure provides place for 114 rights (so 50 more than the previous
cap_rights_t), but it is possible to grow the structure to hold at least 285
rights, although we can make it even larger if 285 rights won't be enough.
The structure definition looks like this:
struct cap_rights {
uint64_t cr_rights[CAP_RIGHTS_VERSION + 2];
};
The initial CAP_RIGHTS_VERSION is 0.
The top two bits in the first element of the cr_rights[] array contain total
number of elements in the array - 2. This means if those two bits are equal to
0, we have 2 array elements.
The top two bits in all remaining array elements should be 0.
The next five bits in all array elements contain array index. Only one bit is
used and bit position in this five-bits range defines array index. This means
there can be at most five array elements in the future.
To define new right the CAPRIGHT() macro must be used. The macro takes two
arguments - an array index and a bit to set, eg.
#define CAP_PDKILL CAPRIGHT(1, 0x0000000000000800ULL)
We still support aliases that combine few rights, but the rights have to belong
to the same array element, eg:
#define CAP_LOOKUP CAPRIGHT(0, 0x0000000000000400ULL)
#define CAP_FCHMOD CAPRIGHT(0, 0x0000000000002000ULL)
#define CAP_FCHMODAT (CAP_FCHMOD | CAP_LOOKUP)
There is new API to manage the new cap_rights_t structure:
cap_rights_t *cap_rights_init(cap_rights_t *rights, ...);
void cap_rights_set(cap_rights_t *rights, ...);
void cap_rights_clear(cap_rights_t *rights, ...);
bool cap_rights_is_set(const cap_rights_t *rights, ...);
bool cap_rights_is_valid(const cap_rights_t *rights);
void cap_rights_merge(cap_rights_t *dst, const cap_rights_t *src);
void cap_rights_remove(cap_rights_t *dst, const cap_rights_t *src);
bool cap_rights_contains(const cap_rights_t *big, const cap_rights_t *little);
Capability rights to the cap_rights_init(), cap_rights_set(),
cap_rights_clear() and cap_rights_is_set() functions are provided by
separating them with commas, eg:
cap_rights_t rights;
cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_FSTAT);
There is no need to terminate the list of rights, as those functions are
actually macros that take care of the termination, eg:
#define cap_rights_set(rights, ...) \
__cap_rights_set((rights), __VA_ARGS__, 0ULL)
void __cap_rights_set(cap_rights_t *rights, ...);
Thanks to using one bit as an array index we can assert in those functions that
there are no two rights belonging to different array elements provided
together. For example this is illegal and will be detected, because CAP_LOOKUP
belongs to element 0 and CAP_PDKILL to element 1:
cap_rights_init(&rights, CAP_LOOKUP | CAP_PDKILL);
Providing several rights that belongs to the same array's element this way is
correct, but is not advised. It should only be used for aliases definition.
This commit also breaks compatibility with some existing Capsicum system calls,
but I see no other way to do that. This should be fine as Capsicum is still
experimental and this change is not going to 9.x.
Sponsored by: The FreeBSD Foundation
2013-09-05 00:09:56 +00:00
|
|
|
error = fget(td, args->fd, cap_rights_init(&rights, CAP_IOCTL), &fp);
|
|
|
|
if (error != 0)
|
2002-01-14 00:13:45 +00:00
|
|
|
return (error);
|
1999-12-04 11:10:22 +00:00
|
|
|
switch (args->cmd & 0xffff) {
|
|
|
|
|
|
|
|
case LINUX_KIOCSOUND:
|
|
|
|
args->cmd = KIOCSOUND;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = (sys_ioctl(td, (struct ioctl_args *)args));
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
case LINUX_KDMKTONE:
|
|
|
|
args->cmd = KDMKTONE;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = (sys_ioctl(td, (struct ioctl_args *)args));
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
case LINUX_KDGETLED:
|
|
|
|
args->cmd = KDGETLED;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = (sys_ioctl(td, (struct ioctl_args *)args));
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
case LINUX_KDSETLED:
|
|
|
|
args->cmd = KDSETLED;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = (sys_ioctl(td, (struct ioctl_args *)args));
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
case LINUX_KDSETMODE:
|
|
|
|
args->cmd = KDSETMODE;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = (sys_ioctl(td, (struct ioctl_args *)args));
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
case LINUX_KDGETMODE:
|
|
|
|
args->cmd = KDGETMODE;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = (sys_ioctl(td, (struct ioctl_args *)args));
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
case LINUX_KDGKBMODE:
|
|
|
|
args->cmd = KDGKBMODE;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = (sys_ioctl(td, (struct ioctl_args *)args));
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
case LINUX_KDSKBMODE: {
|
|
|
|
int kbdmode;
|
|
|
|
switch (args->arg) {
|
|
|
|
case LINUX_KBD_RAW:
|
|
|
|
kbdmode = K_RAW;
|
|
|
|
break;
|
|
|
|
case LINUX_KBD_XLATE:
|
|
|
|
kbdmode = K_XLATE;
|
|
|
|
break;
|
|
|
|
case LINUX_KBD_MEDIUMRAW:
|
|
|
|
kbdmode = K_RAW;
|
|
|
|
break;
|
|
|
|
default:
|
2002-01-13 11:58:06 +00:00
|
|
|
fdrop(fp, td);
|
1999-12-04 11:10:22 +00:00
|
|
|
return (EINVAL);
|
|
|
|
}
|
2002-08-17 02:36:16 +00:00
|
|
|
error = (fo_ioctl(fp, KDSKBMODE, (caddr_t)&kbdmode,
|
|
|
|
td->td_ucred, td));
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1997-12-15 06:09:11 +00:00
|
|
|
}
|
1998-08-31 06:55:02 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
case LINUX_VT_OPENQRY:
|
|
|
|
args->cmd = VT_OPENQRY;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = (sys_ioctl(td, (struct ioctl_args *)args));
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
case LINUX_VT_GETMODE:
|
|
|
|
args->cmd = VT_GETMODE;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = (sys_ioctl(td, (struct ioctl_args *)args));
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
case LINUX_VT_SETMODE: {
|
2004-06-18 13:36:30 +00:00
|
|
|
struct vt_mode mode;
|
|
|
|
if ((error = copyin((void *)args->arg, &mode, sizeof(mode))))
|
|
|
|
break;
|
2015-05-24 17:59:17 +00:00
|
|
|
if (LINUX_SIG_VALID(mode.relsig))
|
|
|
|
mode.relsig = linux_to_bsd_signal(mode.relsig);
|
|
|
|
else
|
|
|
|
mode.relsig = 0;
|
|
|
|
if (LINUX_SIG_VALID(mode.acqsig))
|
|
|
|
mode.acqsig = linux_to_bsd_signal(mode.acqsig);
|
|
|
|
else
|
|
|
|
mode.acqsig = 0;
|
|
|
|
/* XXX. Linux ignores frsig and set it to 0. */
|
|
|
|
mode.frsig = 0;
|
2004-06-18 13:36:30 +00:00
|
|
|
if ((error = copyout(&mode, (void *)args->arg, sizeof(mode))))
|
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
args->cmd = VT_SETMODE;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = (sys_ioctl(td, (struct ioctl_args *)args));
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
}
|
1998-08-31 06:55:02 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
case LINUX_VT_GETSTATE:
|
|
|
|
args->cmd = VT_GETACTIVE;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = (sys_ioctl(td, (struct ioctl_args *)args));
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1998-08-31 06:55:02 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
case LINUX_VT_RELDISP:
|
|
|
|
args->cmd = VT_RELDISP;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = (sys_ioctl(td, (struct ioctl_args *)args));
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1998-08-31 06:55:02 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
case LINUX_VT_ACTIVATE:
|
|
|
|
args->cmd = VT_ACTIVATE;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = (sys_ioctl(td, (struct ioctl_args *)args));
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1998-08-31 06:55:02 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
case LINUX_VT_WAITACTIVE:
|
|
|
|
args->cmd = VT_WAITACTIVE;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = (sys_ioctl(td, (struct ioctl_args *)args));
|
2002-01-13 11:58:06 +00:00
|
|
|
break;
|
1998-08-31 06:55:02 +00:00
|
|
|
|
2002-01-13 11:58:06 +00:00
|
|
|
default:
|
|
|
|
error = ENOIOCTL;
|
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
}
|
2003-03-02 15:56:49 +00:00
|
|
|
|
2002-01-13 11:58:06 +00:00
|
|
|
fdrop(fp, td);
|
|
|
|
return (error);
|
1999-12-04 11:10:22 +00:00
|
|
|
}
|
1999-04-29 04:37:57 +00:00
|
|
|
|
2001-11-19 15:43:50 +00:00
|
|
|
/*
|
|
|
|
* Criteria for interface name translation
|
|
|
|
*/
|
|
|
|
#define IFP_IS_ETH(ifp) (ifp->if_type == IFT_ETHER)
|
2001-10-20 00:01:26 +00:00
|
|
|
|
2001-10-15 20:52:17 +00:00
|
|
|
/*
|
|
|
|
* Translate a Linux interface name to a FreeBSD interface name,
|
|
|
|
* and return the associated ifnet structure
|
|
|
|
* bsdname and lxname need to be least IFNAMSIZ bytes long, but
|
|
|
|
* can point to the same buffer.
|
|
|
|
*/
|
2001-10-20 00:01:26 +00:00
|
|
|
|
2001-10-15 20:52:17 +00:00
|
|
|
static struct ifnet *
|
2009-06-15 19:01:53 +00:00
|
|
|
ifname_linux_to_bsd(struct thread *td, const char *lxname, char *bsdname)
|
2001-10-15 20:52:17 +00:00
|
|
|
{
|
|
|
|
struct ifnet *ifp;
|
|
|
|
int len, unit;
|
|
|
|
char *ep;
|
2001-12-04 03:55:10 +00:00
|
|
|
int is_eth, index;
|
2001-10-15 20:52:17 +00:00
|
|
|
|
|
|
|
for (len = 0; len < LINUX_IFNAMSIZ; ++len)
|
|
|
|
if (!isalpha(lxname[len]))
|
|
|
|
break;
|
|
|
|
if (len == 0 || len == LINUX_IFNAMSIZ)
|
|
|
|
return (NULL);
|
|
|
|
unit = (int)strtoul(lxname + len, &ep, 10);
|
|
|
|
if (ep == NULL || ep == lxname + len || ep >= lxname + LINUX_IFNAMSIZ)
|
|
|
|
return (NULL);
|
2001-12-04 03:55:10 +00:00
|
|
|
index = 0;
|
|
|
|
is_eth = (len == 3 && !strncmp(lxname, "eth", len)) ? 1 : 0;
|
2009-08-28 22:51:07 +00:00
|
|
|
CURVNET_SET(TD_TO_VNET(td));
|
2002-12-22 05:35:03 +00:00
|
|
|
IFNET_RLOCK();
|
Commit step 1 of the vimage project, (network stack)
virtualization work done by Marko Zec (zec@).
This is the first in a series of commits over the course
of the next few weeks.
Mark all uses of global variables to be virtualized
with a V_ prefix.
Use macros to map them back to their global names for
now, so this is a NOP change only.
We hope to have caught at least 85-90% of what is needed
so we do not invalidate a lot of outstanding patches again.
Obtained from: //depot/projects/vimage-commit2/...
Reviewed by: brooks, des, ed, mav, julian,
jamie, kris, rwatson, zec, ...
(various people I forgot, different versions)
md5 (with a bit of help)
Sponsored by: NLnet Foundation, The FreeBSD Foundation
X-MFC after: never
V_Commit_Message_Reviewed_By: more people than the patch
2008-08-17 23:27:27 +00:00
|
|
|
TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
|
2001-12-04 03:55:10 +00:00
|
|
|
/*
|
|
|
|
* Allow Linux programs to use FreeBSD names. Don't presume
|
|
|
|
* we never have an interface named "eth", so don't make
|
|
|
|
* the test optional based on is_eth.
|
|
|
|
*/
|
2003-10-31 18:32:15 +00:00
|
|
|
if (strncmp(ifp->if_xname, lxname, LINUX_IFNAMSIZ) == 0)
|
2001-10-15 20:52:17 +00:00
|
|
|
break;
|
2001-12-04 03:55:10 +00:00
|
|
|
if (is_eth && IFP_IS_ETH(ifp) && unit == index++)
|
2001-10-15 20:52:17 +00:00
|
|
|
break;
|
|
|
|
}
|
2002-12-22 05:35:03 +00:00
|
|
|
IFNET_RUNLOCK();
|
2009-08-28 22:51:07 +00:00
|
|
|
CURVNET_RESTORE();
|
2001-10-15 20:52:17 +00:00
|
|
|
if (ifp != NULL)
|
2003-10-31 18:32:15 +00:00
|
|
|
strlcpy(bsdname, ifp->if_xname, IFNAMSIZ);
|
2001-10-15 20:52:17 +00:00
|
|
|
return (ifp);
|
|
|
|
}
|
|
|
|
|
2017-04-09 15:27:04 +00:00
|
|
|
/*
|
|
|
|
* Implement the SIOCGIFNAME ioctl
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int
|
|
|
|
linux_ioctl_ifname(struct thread *td, struct l_ifreq *uifr)
|
|
|
|
{
|
|
|
|
struct l_ifreq ifr;
|
|
|
|
struct ifnet *ifp;
|
|
|
|
int error, ethno, index;
|
|
|
|
|
|
|
|
error = copyin(uifr, &ifr, sizeof(ifr));
|
|
|
|
if (error != 0)
|
|
|
|
return (error);
|
|
|
|
|
|
|
|
CURVNET_SET(TD_TO_VNET(curthread));
|
|
|
|
IFNET_RLOCK();
|
|
|
|
index = 1; /* ifr.ifr_ifindex starts from 1 */
|
|
|
|
ethno = 0;
|
|
|
|
error = ENODEV;
|
|
|
|
TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
|
|
|
|
if (ifr.ifr_ifindex == index) {
|
|
|
|
if (IFP_IS_ETH(ifp))
|
|
|
|
snprintf(ifr.ifr_name, LINUX_IFNAMSIZ,
|
|
|
|
"eth%d", ethno);
|
|
|
|
else
|
|
|
|
strlcpy(ifr.ifr_name, ifp->if_xname,
|
|
|
|
LINUX_IFNAMSIZ);
|
|
|
|
error = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (IFP_IS_ETH(ifp))
|
|
|
|
ethno++;
|
|
|
|
index++;
|
|
|
|
}
|
|
|
|
IFNET_RUNLOCK();
|
|
|
|
if (error == 0)
|
|
|
|
error = copyout(&ifr, uifr, sizeof(ifr));
|
|
|
|
CURVNET_RESTORE();
|
|
|
|
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
2001-10-15 20:52:17 +00:00
|
|
|
/*
|
|
|
|
* Implement the SIOCGIFCONF ioctl
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int
|
|
|
|
linux_ifconf(struct thread *td, struct ifconf *uifc)
|
|
|
|
{
|
2005-01-14 04:44:56 +00:00
|
|
|
#ifdef COMPAT_LINUX32
|
2004-08-16 07:28:16 +00:00
|
|
|
struct l_ifconf ifc;
|
|
|
|
#else
|
2001-10-15 20:52:17 +00:00
|
|
|
struct ifconf ifc;
|
2004-08-16 07:28:16 +00:00
|
|
|
#endif
|
2001-10-15 20:52:17 +00:00
|
|
|
struct l_ifreq ifr;
|
|
|
|
struct ifnet *ifp;
|
2002-01-29 06:00:11 +00:00
|
|
|
struct ifaddr *ifa;
|
2005-08-27 14:44:10 +00:00
|
|
|
struct sbuf *sb;
|
|
|
|
int error, ethno, full = 0, valid_len, max_len;
|
2002-01-10 05:36:36 +00:00
|
|
|
|
2003-03-03 09:14:26 +00:00
|
|
|
error = copyin(uifc, &ifc, sizeof(ifc));
|
2001-10-15 20:52:17 +00:00
|
|
|
if (error != 0)
|
|
|
|
return (error);
|
|
|
|
|
2005-08-27 14:44:10 +00:00
|
|
|
max_len = MAXPHYS - 1;
|
|
|
|
|
2009-08-28 22:51:07 +00:00
|
|
|
CURVNET_SET(TD_TO_VNET(td));
|
2004-06-18 14:06:46 +00:00
|
|
|
/* handle the 'request buffer size' case */
|
2012-01-03 18:49:39 +00:00
|
|
|
if ((l_uintptr_t)ifc.ifc_buf == PTROUT(NULL)) {
|
2004-06-18 14:06:46 +00:00
|
|
|
ifc.ifc_len = 0;
|
2009-09-13 21:30:18 +00:00
|
|
|
IFNET_RLOCK();
|
Commit step 1 of the vimage project, (network stack)
virtualization work done by Marko Zec (zec@).
This is the first in a series of commits over the course
of the next few weeks.
Mark all uses of global variables to be virtualized
with a V_ prefix.
Use macros to map them back to their global names for
now, so this is a NOP change only.
We hope to have caught at least 85-90% of what is needed
so we do not invalidate a lot of outstanding patches again.
Obtained from: //depot/projects/vimage-commit2/...
Reviewed by: brooks, des, ed, mav, julian,
jamie, kris, rwatson, zec, ...
(various people I forgot, different versions)
md5 (with a bit of help)
Sponsored by: NLnet Foundation, The FreeBSD Foundation
X-MFC after: never
V_Commit_Message_Reviewed_By: more people than the patch
2008-08-17 23:27:27 +00:00
|
|
|
TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
|
2004-06-18 14:06:46 +00:00
|
|
|
TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
|
|
|
|
struct sockaddr *sa = ifa->ifa_addr;
|
|
|
|
if (sa->sa_family == AF_INET)
|
|
|
|
ifc.ifc_len += sizeof(ifr);
|
|
|
|
}
|
|
|
|
}
|
2009-09-13 21:30:18 +00:00
|
|
|
IFNET_RUNLOCK();
|
2004-06-18 14:06:46 +00:00
|
|
|
error = copyout(&ifc, uifc, sizeof(ifc));
|
2009-08-28 22:51:07 +00:00
|
|
|
CURVNET_RESTORE();
|
2004-06-18 14:06:46 +00:00
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
2009-08-28 22:51:07 +00:00
|
|
|
if (ifc.ifc_len <= 0) {
|
|
|
|
CURVNET_RESTORE();
|
2005-08-27 14:44:10 +00:00
|
|
|
return (EINVAL);
|
2009-08-28 22:51:07 +00:00
|
|
|
}
|
2001-10-15 20:52:17 +00:00
|
|
|
|
2005-08-27 14:44:10 +00:00
|
|
|
again:
|
2002-01-10 05:36:36 +00:00
|
|
|
/* Keep track of eth interfaces */
|
|
|
|
ethno = 0;
|
2005-08-27 14:44:10 +00:00
|
|
|
if (ifc.ifc_len <= max_len) {
|
|
|
|
max_len = ifc.ifc_len;
|
|
|
|
full = 1;
|
|
|
|
}
|
|
|
|
sb = sbuf_new(NULL, NULL, max_len + 1, SBUF_FIXEDLEN);
|
|
|
|
max_len = 0;
|
|
|
|
valid_len = 0;
|
2002-01-10 05:36:36 +00:00
|
|
|
|
2002-01-29 06:00:11 +00:00
|
|
|
/* Return all AF_INET addresses of all interfaces */
|
2009-08-23 20:40:19 +00:00
|
|
|
IFNET_RLOCK();
|
Commit step 1 of the vimage project, (network stack)
virtualization work done by Marko Zec (zec@).
This is the first in a series of commits over the course
of the next few weeks.
Mark all uses of global variables to be virtualized
with a V_ prefix.
Use macros to map them back to their global names for
now, so this is a NOP change only.
We hope to have caught at least 85-90% of what is needed
so we do not invalidate a lot of outstanding patches again.
Obtained from: //depot/projects/vimage-commit2/...
Reviewed by: brooks, des, ed, mav, julian,
jamie, kris, rwatson, zec, ...
(various people I forgot, different versions)
md5 (with a bit of help)
Sponsored by: NLnet Foundation, The FreeBSD Foundation
X-MFC after: never
V_Commit_Message_Reviewed_By: more people than the patch
2008-08-17 23:27:27 +00:00
|
|
|
TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
|
2005-08-27 14:44:10 +00:00
|
|
|
int addrs = 0;
|
2002-01-29 06:00:11 +00:00
|
|
|
|
2003-03-03 09:14:26 +00:00
|
|
|
bzero(&ifr, sizeof(ifr));
|
2002-01-10 05:36:36 +00:00
|
|
|
if (IFP_IS_ETH(ifp))
|
|
|
|
snprintf(ifr.ifr_name, LINUX_IFNAMSIZ, "eth%d",
|
|
|
|
ethno++);
|
|
|
|
else
|
2003-10-31 18:32:15 +00:00
|
|
|
strlcpy(ifr.ifr_name, ifp->if_xname, LINUX_IFNAMSIZ);
|
2002-01-29 06:00:11 +00:00
|
|
|
|
|
|
|
/* Walk the address list */
|
|
|
|
TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
|
|
|
|
struct sockaddr *sa = ifa->ifa_addr;
|
|
|
|
|
|
|
|
if (sa->sa_family == AF_INET) {
|
|
|
|
ifr.ifr_addr.sa_family = LINUX_AF_INET;
|
|
|
|
memcpy(ifr.ifr_addr.sa_data, sa->sa_data,
|
|
|
|
sizeof(ifr.ifr_addr.sa_data));
|
2005-08-27 14:44:10 +00:00
|
|
|
sbuf_bcat(sb, &ifr, sizeof(ifr));
|
|
|
|
max_len += sizeof(ifr);
|
|
|
|
addrs++;
|
2002-01-29 06:00:11 +00:00
|
|
|
}
|
2005-08-27 14:44:10 +00:00
|
|
|
|
2010-09-10 16:42:16 +00:00
|
|
|
if (sbuf_error(sb) == 0)
|
2005-08-27 14:44:10 +00:00
|
|
|
valid_len = sbuf_len(sb);
|
|
|
|
}
|
|
|
|
if (addrs == 0) {
|
|
|
|
bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
|
|
|
|
sbuf_bcat(sb, &ifr, sizeof(ifr));
|
|
|
|
max_len += sizeof(ifr);
|
|
|
|
|
2010-09-10 16:42:16 +00:00
|
|
|
if (sbuf_error(sb) == 0)
|
2005-08-27 14:44:10 +00:00
|
|
|
valid_len = sbuf_len(sb);
|
2002-01-29 06:00:11 +00:00
|
|
|
}
|
2001-10-15 20:52:17 +00:00
|
|
|
}
|
2002-12-22 05:35:03 +00:00
|
|
|
IFNET_RUNLOCK();
|
2001-10-15 20:52:17 +00:00
|
|
|
|
2005-08-27 14:44:10 +00:00
|
|
|
if (valid_len != max_len && !full) {
|
|
|
|
sbuf_delete(sb);
|
|
|
|
goto again;
|
|
|
|
}
|
|
|
|
|
2018-02-05 17:29:12 +00:00
|
|
|
ifc.ifc_len = valid_len;
|
2005-08-27 14:44:10 +00:00
|
|
|
sbuf_finish(sb);
|
2012-11-23 01:48:31 +00:00
|
|
|
error = copyout(sbuf_data(sb), PTRIN(ifc.ifc_buf), ifc.ifc_len);
|
|
|
|
if (error == 0)
|
|
|
|
error = copyout(&ifc, uifc, sizeof(ifc));
|
2005-08-27 14:44:10 +00:00
|
|
|
sbuf_delete(sb);
|
2009-08-28 22:51:07 +00:00
|
|
|
CURVNET_RESTORE();
|
2002-01-10 05:36:36 +00:00
|
|
|
|
2001-10-15 20:52:17 +00:00
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
linux_gifflags(struct thread *td, struct ifnet *ifp, struct l_ifreq *ifr)
|
|
|
|
{
|
|
|
|
l_short flags;
|
|
|
|
|
2005-08-09 10:20:02 +00:00
|
|
|
flags = (ifp->if_flags | ifp->if_drv_flags) & 0xffff;
|
2001-10-15 20:52:17 +00:00
|
|
|
/* these flags have no Linux equivalent */
|
2013-11-05 12:52:56 +00:00
|
|
|
flags &= ~(IFF_DRV_OACTIVE|IFF_SIMPLEX|
|
2001-10-15 20:52:17 +00:00
|
|
|
IFF_LINK0|IFF_LINK1|IFF_LINK2);
|
|
|
|
/* Linux' multicast flag is in a different bit */
|
|
|
|
if (flags & IFF_MULTICAST) {
|
|
|
|
flags &= ~IFF_MULTICAST;
|
|
|
|
flags |= 0x1000;
|
|
|
|
}
|
|
|
|
|
2003-03-03 09:14:26 +00:00
|
|
|
return (copyout(&flags, &ifr->ifr_flags, sizeof(flags)));
|
2001-10-15 20:52:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#define ARPHRD_ETHER 1
|
|
|
|
#define ARPHRD_LOOPBACK 772
|
|
|
|
|
|
|
|
static int
|
2001-10-20 00:01:26 +00:00
|
|
|
linux_gifhwaddr(struct ifnet *ifp, struct l_ifreq *ifr)
|
2001-10-15 20:52:17 +00:00
|
|
|
{
|
|
|
|
struct ifaddr *ifa;
|
|
|
|
struct sockaddr_dl *sdl;
|
|
|
|
struct l_sockaddr lsa;
|
|
|
|
|
|
|
|
if (ifp->if_type == IFT_LOOP) {
|
2003-03-03 09:14:26 +00:00
|
|
|
bzero(&lsa, sizeof(lsa));
|
2001-10-15 20:52:17 +00:00
|
|
|
lsa.sa_family = ARPHRD_LOOPBACK;
|
2003-03-03 09:14:26 +00:00
|
|
|
return (copyout(&lsa, &ifr->ifr_hwaddr, sizeof(lsa)));
|
2001-10-15 20:52:17 +00:00
|
|
|
}
|
2003-03-02 15:56:49 +00:00
|
|
|
|
2001-10-15 20:52:17 +00:00
|
|
|
if (ifp->if_type != IFT_ETHER)
|
|
|
|
return (ENOENT);
|
|
|
|
|
|
|
|
TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
|
|
|
|
sdl = (struct sockaddr_dl*)ifa->ifa_addr;
|
|
|
|
if (sdl != NULL && (sdl->sdl_family == AF_LINK) &&
|
|
|
|
(sdl->sdl_type == IFT_ETHER)) {
|
2003-03-03 09:14:26 +00:00
|
|
|
bzero(&lsa, sizeof(lsa));
|
2001-10-15 20:52:17 +00:00
|
|
|
lsa.sa_family = ARPHRD_ETHER;
|
|
|
|
bcopy(LLADDR(sdl), lsa.sa_data, LINUX_IFHWADDRLEN);
|
2003-03-03 09:14:26 +00:00
|
|
|
return (copyout(&lsa, &ifr->ifr_hwaddr, sizeof(lsa)));
|
2001-10-15 20:52:17 +00:00
|
|
|
}
|
|
|
|
}
|
2003-03-02 15:56:49 +00:00
|
|
|
|
2001-10-15 20:52:17 +00:00
|
|
|
return (ENOENT);
|
|
|
|
}
|
|
|
|
|
2006-03-18 18:20:17 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If we fault in bsd_to_linux_ifreq() then we will fault when we call
|
|
|
|
* the native ioctl(). Thus, we don't really need to check the return
|
|
|
|
* value of this function.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
bsd_to_linux_ifreq(struct ifreq *arg)
|
|
|
|
{
|
|
|
|
struct ifreq ifr;
|
|
|
|
size_t ifr_len = sizeof(struct ifreq);
|
|
|
|
int error;
|
2018-02-05 17:29:12 +00:00
|
|
|
|
2006-03-18 18:20:17 +00:00
|
|
|
if ((error = copyin(arg, &ifr, ifr_len)))
|
|
|
|
return (error);
|
2018-02-05 17:29:12 +00:00
|
|
|
|
2006-03-18 18:20:17 +00:00
|
|
|
*(u_short *)&ifr.ifr_addr = ifr.ifr_addr.sa_family;
|
2018-02-05 17:29:12 +00:00
|
|
|
|
2006-03-18 18:20:17 +00:00
|
|
|
error = copyout(&ifr, arg, ifr_len);
|
|
|
|
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
/*
|
|
|
|
* Socket related ioctls
|
|
|
|
*/
|
1999-04-29 04:37:57 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
static int
|
2001-09-12 08:38:13 +00:00
|
|
|
linux_ioctl_socket(struct thread *td, struct linux_ioctl_args *args)
|
1999-12-04 11:10:22 +00:00
|
|
|
{
|
2001-10-15 20:52:17 +00:00
|
|
|
char lifname[LINUX_IFNAMSIZ], ifname[IFNAMSIZ];
|
Change the cap_rights_t type from uint64_t to a structure that we can extend
in the future in a backward compatible (API and ABI) way.
The cap_rights_t represents capability rights. We used to use one bit to
represent one right, but we are running out of spare bits. Currently the new
structure provides place for 114 rights (so 50 more than the previous
cap_rights_t), but it is possible to grow the structure to hold at least 285
rights, although we can make it even larger if 285 rights won't be enough.
The structure definition looks like this:
struct cap_rights {
uint64_t cr_rights[CAP_RIGHTS_VERSION + 2];
};
The initial CAP_RIGHTS_VERSION is 0.
The top two bits in the first element of the cr_rights[] array contain total
number of elements in the array - 2. This means if those two bits are equal to
0, we have 2 array elements.
The top two bits in all remaining array elements should be 0.
The next five bits in all array elements contain array index. Only one bit is
used and bit position in this five-bits range defines array index. This means
there can be at most five array elements in the future.
To define new right the CAPRIGHT() macro must be used. The macro takes two
arguments - an array index and a bit to set, eg.
#define CAP_PDKILL CAPRIGHT(1, 0x0000000000000800ULL)
We still support aliases that combine few rights, but the rights have to belong
to the same array element, eg:
#define CAP_LOOKUP CAPRIGHT(0, 0x0000000000000400ULL)
#define CAP_FCHMOD CAPRIGHT(0, 0x0000000000002000ULL)
#define CAP_FCHMODAT (CAP_FCHMOD | CAP_LOOKUP)
There is new API to manage the new cap_rights_t structure:
cap_rights_t *cap_rights_init(cap_rights_t *rights, ...);
void cap_rights_set(cap_rights_t *rights, ...);
void cap_rights_clear(cap_rights_t *rights, ...);
bool cap_rights_is_set(const cap_rights_t *rights, ...);
bool cap_rights_is_valid(const cap_rights_t *rights);
void cap_rights_merge(cap_rights_t *dst, const cap_rights_t *src);
void cap_rights_remove(cap_rights_t *dst, const cap_rights_t *src);
bool cap_rights_contains(const cap_rights_t *big, const cap_rights_t *little);
Capability rights to the cap_rights_init(), cap_rights_set(),
cap_rights_clear() and cap_rights_is_set() functions are provided by
separating them with commas, eg:
cap_rights_t rights;
cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_FSTAT);
There is no need to terminate the list of rights, as those functions are
actually macros that take care of the termination, eg:
#define cap_rights_set(rights, ...) \
__cap_rights_set((rights), __VA_ARGS__, 0ULL)
void __cap_rights_set(cap_rights_t *rights, ...);
Thanks to using one bit as an array index we can assert in those functions that
there are no two rights belonging to different array elements provided
together. For example this is illegal and will be detected, because CAP_LOOKUP
belongs to element 0 and CAP_PDKILL to element 1:
cap_rights_init(&rights, CAP_LOOKUP | CAP_PDKILL);
Providing several rights that belongs to the same array's element this way is
correct, but is not advised. It should only be used for aliases definition.
This commit also breaks compatibility with some existing Capsicum system calls,
but I see no other way to do that. This should be fine as Capsicum is still
experimental and this change is not going to 9.x.
Sponsored by: The FreeBSD Foundation
2013-09-05 00:09:56 +00:00
|
|
|
cap_rights_t rights;
|
2001-10-15 20:52:17 +00:00
|
|
|
struct ifnet *ifp;
|
2001-11-19 15:43:50 +00:00
|
|
|
struct file *fp;
|
|
|
|
int error, type;
|
2001-10-15 20:52:17 +00:00
|
|
|
|
|
|
|
ifp = NULL;
|
|
|
|
error = 0;
|
2003-03-02 15:56:49 +00:00
|
|
|
|
Change the cap_rights_t type from uint64_t to a structure that we can extend
in the future in a backward compatible (API and ABI) way.
The cap_rights_t represents capability rights. We used to use one bit to
represent one right, but we are running out of spare bits. Currently the new
structure provides place for 114 rights (so 50 more than the previous
cap_rights_t), but it is possible to grow the structure to hold at least 285
rights, although we can make it even larger if 285 rights won't be enough.
The structure definition looks like this:
struct cap_rights {
uint64_t cr_rights[CAP_RIGHTS_VERSION + 2];
};
The initial CAP_RIGHTS_VERSION is 0.
The top two bits in the first element of the cr_rights[] array contain total
number of elements in the array - 2. This means if those two bits are equal to
0, we have 2 array elements.
The top two bits in all remaining array elements should be 0.
The next five bits in all array elements contain array index. Only one bit is
used and bit position in this five-bits range defines array index. This means
there can be at most five array elements in the future.
To define new right the CAPRIGHT() macro must be used. The macro takes two
arguments - an array index and a bit to set, eg.
#define CAP_PDKILL CAPRIGHT(1, 0x0000000000000800ULL)
We still support aliases that combine few rights, but the rights have to belong
to the same array element, eg:
#define CAP_LOOKUP CAPRIGHT(0, 0x0000000000000400ULL)
#define CAP_FCHMOD CAPRIGHT(0, 0x0000000000002000ULL)
#define CAP_FCHMODAT (CAP_FCHMOD | CAP_LOOKUP)
There is new API to manage the new cap_rights_t structure:
cap_rights_t *cap_rights_init(cap_rights_t *rights, ...);
void cap_rights_set(cap_rights_t *rights, ...);
void cap_rights_clear(cap_rights_t *rights, ...);
bool cap_rights_is_set(const cap_rights_t *rights, ...);
bool cap_rights_is_valid(const cap_rights_t *rights);
void cap_rights_merge(cap_rights_t *dst, const cap_rights_t *src);
void cap_rights_remove(cap_rights_t *dst, const cap_rights_t *src);
bool cap_rights_contains(const cap_rights_t *big, const cap_rights_t *little);
Capability rights to the cap_rights_init(), cap_rights_set(),
cap_rights_clear() and cap_rights_is_set() functions are provided by
separating them with commas, eg:
cap_rights_t rights;
cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_FSTAT);
There is no need to terminate the list of rights, as those functions are
actually macros that take care of the termination, eg:
#define cap_rights_set(rights, ...) \
__cap_rights_set((rights), __VA_ARGS__, 0ULL)
void __cap_rights_set(cap_rights_t *rights, ...);
Thanks to using one bit as an array index we can assert in those functions that
there are no two rights belonging to different array elements provided
together. For example this is illegal and will be detected, because CAP_LOOKUP
belongs to element 0 and CAP_PDKILL to element 1:
cap_rights_init(&rights, CAP_LOOKUP | CAP_PDKILL);
Providing several rights that belongs to the same array's element this way is
correct, but is not advised. It should only be used for aliases definition.
This commit also breaks compatibility with some existing Capsicum system calls,
but I see no other way to do that. This should be fine as Capsicum is still
experimental and this change is not going to 9.x.
Sponsored by: The FreeBSD Foundation
2013-09-05 00:09:56 +00:00
|
|
|
error = fget(td, args->fd, cap_rights_init(&rights, CAP_IOCTL), &fp);
|
|
|
|
if (error != 0)
|
2001-11-19 15:43:50 +00:00
|
|
|
return (error);
|
|
|
|
type = fp->f_type;
|
|
|
|
fdrop(fp, td);
|
|
|
|
if (type != DTYPE_SOCKET) {
|
|
|
|
/* not a socket - probably a tap / vmnet device */
|
|
|
|
switch (args->cmd) {
|
|
|
|
case LINUX_SIOCGIFADDR:
|
|
|
|
case LINUX_SIOCSIFADDR:
|
|
|
|
case LINUX_SIOCGIFFLAGS:
|
|
|
|
return (linux_ioctl_special(td, args));
|
|
|
|
default:
|
|
|
|
return (ENOIOCTL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-10-15 20:52:17 +00:00
|
|
|
switch (args->cmd & 0xffff) {
|
2003-03-02 15:56:49 +00:00
|
|
|
|
2001-10-15 20:52:17 +00:00
|
|
|
case LINUX_FIOGETOWN:
|
|
|
|
case LINUX_FIOSETOWN:
|
|
|
|
case LINUX_SIOCADDMULTI:
|
|
|
|
case LINUX_SIOCATMARK:
|
|
|
|
case LINUX_SIOCDELMULTI:
|
2017-04-09 15:27:04 +00:00
|
|
|
case LINUX_SIOCGIFNAME:
|
2001-10-15 20:52:17 +00:00
|
|
|
case LINUX_SIOCGIFCONF:
|
|
|
|
case LINUX_SIOCGPGRP:
|
|
|
|
case LINUX_SIOCSPGRP:
|
2007-11-07 16:42:52 +00:00
|
|
|
case LINUX_SIOCGIFCOUNT:
|
2001-10-15 20:52:17 +00:00
|
|
|
/* these ioctls don't take an interface name */
|
|
|
|
#ifdef DEBUG
|
2001-12-10 08:09:49 +00:00
|
|
|
printf("%s(): ioctl %d\n", __func__,
|
2001-10-15 20:52:17 +00:00
|
|
|
args->cmd & 0xffff);
|
|
|
|
#endif
|
|
|
|
break;
|
2003-03-02 15:56:49 +00:00
|
|
|
|
2001-10-20 00:01:26 +00:00
|
|
|
case LINUX_SIOCGIFFLAGS:
|
2001-10-15 20:52:17 +00:00
|
|
|
case LINUX_SIOCGIFADDR:
|
2001-11-19 15:43:50 +00:00
|
|
|
case LINUX_SIOCSIFADDR:
|
2001-10-15 20:52:17 +00:00
|
|
|
case LINUX_SIOCGIFDSTADDR:
|
2001-10-20 00:01:26 +00:00
|
|
|
case LINUX_SIOCGIFBRDADDR:
|
2001-10-15 20:52:17 +00:00
|
|
|
case LINUX_SIOCGIFNETMASK:
|
2001-10-20 00:01:26 +00:00
|
|
|
case LINUX_SIOCSIFNETMASK:
|
|
|
|
case LINUX_SIOCGIFMTU:
|
|
|
|
case LINUX_SIOCSIFMTU:
|
|
|
|
case LINUX_SIOCSIFNAME:
|
|
|
|
case LINUX_SIOCGIFHWADDR:
|
|
|
|
case LINUX_SIOCSIFHWADDR:
|
|
|
|
case LINUX_SIOCDEVPRIVATE:
|
|
|
|
case LINUX_SIOCDEVPRIVATE+1:
|
2007-11-07 16:42:52 +00:00
|
|
|
case LINUX_SIOCGIFINDEX:
|
2001-10-15 20:52:17 +00:00
|
|
|
/* copy in the interface name and translate it. */
|
2003-03-03 09:14:26 +00:00
|
|
|
error = copyin((void *)args->arg, lifname, LINUX_IFNAMSIZ);
|
2001-10-20 00:01:26 +00:00
|
|
|
if (error != 0)
|
|
|
|
return (error);
|
2001-10-15 20:52:17 +00:00
|
|
|
#ifdef DEBUG
|
2001-12-10 08:09:49 +00:00
|
|
|
printf("%s(): ioctl %d on %.*s\n", __func__,
|
2001-10-15 20:52:17 +00:00
|
|
|
args->cmd & 0xffff, LINUX_IFNAMSIZ, lifname);
|
|
|
|
#endif
|
2018-04-04 19:58:25 +00:00
|
|
|
memset(ifname, 0, sizeof(ifname));
|
2009-06-15 19:01:53 +00:00
|
|
|
ifp = ifname_linux_to_bsd(td, lifname, ifname);
|
2001-10-15 20:52:17 +00:00
|
|
|
if (ifp == NULL)
|
|
|
|
return (EINVAL);
|
|
|
|
/*
|
|
|
|
* We need to copy it back out in case we pass the
|
|
|
|
* request on to our native ioctl(), which will expect
|
|
|
|
* the ifreq to be in user space and have the correct
|
|
|
|
* interface name.
|
|
|
|
*/
|
2003-03-03 09:14:26 +00:00
|
|
|
error = copyout(ifname, (void *)args->arg, IFNAMSIZ);
|
2001-10-20 00:01:26 +00:00
|
|
|
if (error != 0)
|
|
|
|
return (error);
|
2001-10-15 20:52:17 +00:00
|
|
|
#ifdef DEBUG
|
2001-12-10 08:09:49 +00:00
|
|
|
printf("%s(): %s translated to %s\n", __func__,
|
2001-10-15 20:52:17 +00:00
|
|
|
lifname, ifname);
|
|
|
|
#endif
|
|
|
|
break;
|
2003-03-02 15:56:49 +00:00
|
|
|
|
2001-10-15 20:52:17 +00:00
|
|
|
default:
|
|
|
|
return (ENOIOCTL);
|
|
|
|
}
|
1999-04-29 04:37:57 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
switch (args->cmd & 0xffff) {
|
|
|
|
|
|
|
|
case LINUX_FIOSETOWN:
|
|
|
|
args->cmd = FIOSETOWN;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = sys_ioctl(td, (struct ioctl_args *)args);
|
2001-10-15 20:52:17 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
case LINUX_SIOCSPGRP:
|
|
|
|
args->cmd = SIOCSPGRP;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = sys_ioctl(td, (struct ioctl_args *)args);
|
2001-10-15 20:52:17 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
case LINUX_FIOGETOWN:
|
|
|
|
args->cmd = FIOGETOWN;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = sys_ioctl(td, (struct ioctl_args *)args);
|
2001-10-15 20:52:17 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
case LINUX_SIOCGPGRP:
|
|
|
|
args->cmd = SIOCGPGRP;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = sys_ioctl(td, (struct ioctl_args *)args);
|
2001-10-15 20:52:17 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
case LINUX_SIOCATMARK:
|
|
|
|
args->cmd = SIOCATMARK;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = sys_ioctl(td, (struct ioctl_args *)args);
|
2001-10-15 20:52:17 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
/* LINUX_SIOCGSTAMP */
|
|
|
|
|
2017-04-09 15:27:04 +00:00
|
|
|
case LINUX_SIOCGIFNAME:
|
|
|
|
error = linux_ioctl_ifname(td, (struct l_ifreq *)args->arg);
|
|
|
|
break;
|
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
case LINUX_SIOCGIFCONF:
|
2001-10-15 20:52:17 +00:00
|
|
|
error = linux_ifconf(td, (struct ifconf *)args->arg);
|
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
case LINUX_SIOCGIFFLAGS:
|
|
|
|
args->cmd = SIOCGIFFLAGS;
|
2001-10-15 20:52:17 +00:00
|
|
|
error = linux_gifflags(td, ifp, (struct l_ifreq *)args->arg);
|
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
case LINUX_SIOCGIFADDR:
|
2006-03-18 18:20:17 +00:00
|
|
|
args->cmd = SIOCGIFADDR;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = sys_ioctl(td, (struct ioctl_args *)args);
|
2006-03-18 18:20:17 +00:00
|
|
|
bsd_to_linux_ifreq((struct ifreq *)args->arg);
|
2001-10-15 20:52:17 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
|
2001-11-19 15:43:50 +00:00
|
|
|
case LINUX_SIOCSIFADDR:
|
|
|
|
/* XXX probably doesn't work, included for completeness */
|
|
|
|
args->cmd = SIOCSIFADDR;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = sys_ioctl(td, (struct ioctl_args *)args);
|
2001-11-19 15:43:50 +00:00
|
|
|
break;
|
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
case LINUX_SIOCGIFDSTADDR:
|
2006-03-18 18:20:17 +00:00
|
|
|
args->cmd = SIOCGIFDSTADDR;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = sys_ioctl(td, (struct ioctl_args *)args);
|
2006-03-18 18:20:17 +00:00
|
|
|
bsd_to_linux_ifreq((struct ifreq *)args->arg);
|
2001-10-15 20:52:17 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
case LINUX_SIOCGIFBRDADDR:
|
2006-03-18 18:20:17 +00:00
|
|
|
args->cmd = SIOCGIFBRDADDR;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = sys_ioctl(td, (struct ioctl_args *)args);
|
2006-03-18 18:20:17 +00:00
|
|
|
bsd_to_linux_ifreq((struct ifreq *)args->arg);
|
2001-10-15 20:52:17 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
case LINUX_SIOCGIFNETMASK:
|
2006-03-18 18:20:17 +00:00
|
|
|
args->cmd = SIOCGIFNETMASK;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = sys_ioctl(td, (struct ioctl_args *)args);
|
2006-03-18 18:20:17 +00:00
|
|
|
bsd_to_linux_ifreq((struct ifreq *)args->arg);
|
2001-10-15 20:52:17 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
|
2001-10-20 00:01:26 +00:00
|
|
|
case LINUX_SIOCSIFNETMASK:
|
|
|
|
error = ENOIOCTL;
|
|
|
|
break;
|
2003-03-02 15:56:49 +00:00
|
|
|
|
2001-10-20 00:01:26 +00:00
|
|
|
case LINUX_SIOCGIFMTU:
|
|
|
|
args->cmd = SIOCGIFMTU;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = sys_ioctl(td, (struct ioctl_args *)args);
|
2001-10-20 00:01:26 +00:00
|
|
|
break;
|
2003-03-02 15:56:49 +00:00
|
|
|
|
2001-10-20 00:01:26 +00:00
|
|
|
case LINUX_SIOCSIFMTU:
|
|
|
|
args->cmd = SIOCSIFMTU;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = sys_ioctl(td, (struct ioctl_args *)args);
|
2001-10-20 00:01:26 +00:00
|
|
|
break;
|
2003-03-02 15:56:49 +00:00
|
|
|
|
2001-10-20 00:01:26 +00:00
|
|
|
case LINUX_SIOCSIFNAME:
|
|
|
|
error = ENOIOCTL;
|
|
|
|
break;
|
2003-03-02 15:56:49 +00:00
|
|
|
|
2001-10-15 20:52:17 +00:00
|
|
|
case LINUX_SIOCGIFHWADDR:
|
2001-10-20 00:01:26 +00:00
|
|
|
error = linux_gifhwaddr(ifp, (struct l_ifreq *)args->arg);
|
2001-10-15 20:52:17 +00:00
|
|
|
break;
|
1999-04-29 04:37:57 +00:00
|
|
|
|
2001-10-20 00:01:26 +00:00
|
|
|
case LINUX_SIOCSIFHWADDR:
|
|
|
|
error = ENOIOCTL;
|
|
|
|
break;
|
2003-03-02 15:56:49 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
case LINUX_SIOCADDMULTI:
|
|
|
|
args->cmd = SIOCADDMULTI;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = sys_ioctl(td, (struct ioctl_args *)args);
|
2001-10-15 20:52:17 +00:00
|
|
|
break;
|
1999-04-29 04:37:57 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
case LINUX_SIOCDELMULTI:
|
|
|
|
args->cmd = SIOCDELMULTI;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = sys_ioctl(td, (struct ioctl_args *)args);
|
2001-10-15 20:52:17 +00:00
|
|
|
break;
|
2001-10-19 01:38:10 +00:00
|
|
|
|
2007-11-07 16:42:52 +00:00
|
|
|
case LINUX_SIOCGIFINDEX:
|
|
|
|
args->cmd = SIOCGIFINDEX;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = sys_ioctl(td, (struct ioctl_args *)args);
|
2007-11-07 16:42:52 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case LINUX_SIOCGIFCOUNT:
|
|
|
|
error = 0;
|
|
|
|
break;
|
|
|
|
|
2001-10-19 01:38:10 +00:00
|
|
|
/*
|
|
|
|
* XXX This is slightly bogus, but these ioctls are currently
|
|
|
|
* XXX only used by the aironet (if_an) network driver.
|
|
|
|
*/
|
2001-10-20 00:01:26 +00:00
|
|
|
case LINUX_SIOCDEVPRIVATE:
|
|
|
|
args->cmd = SIOCGPRIVATE_0;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = sys_ioctl(td, (struct ioctl_args *)args);
|
2001-10-20 00:01:26 +00:00
|
|
|
break;
|
2003-03-02 15:56:49 +00:00
|
|
|
|
2001-10-20 00:01:26 +00:00
|
|
|
case LINUX_SIOCDEVPRIVATE+1:
|
|
|
|
args->cmd = SIOCGPRIVATE_1;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = sys_ioctl(td, (struct ioctl_args *)args);
|
2001-10-20 00:01:26 +00:00
|
|
|
break;
|
1999-12-04 11:10:22 +00:00
|
|
|
}
|
1999-04-29 04:37:57 +00:00
|
|
|
|
2001-10-15 20:52:17 +00:00
|
|
|
if (ifp != NULL)
|
|
|
|
/* restore the original interface name */
|
2003-03-03 09:14:26 +00:00
|
|
|
copyout(lifname, (void *)args->arg, LINUX_IFNAMSIZ);
|
2001-10-15 20:52:17 +00:00
|
|
|
|
|
|
|
#ifdef DEBUG
|
2001-12-10 08:09:49 +00:00
|
|
|
printf("%s(): returning %d\n", __func__, error);
|
2001-10-15 20:52:17 +00:00
|
|
|
#endif
|
|
|
|
return (error);
|
1999-12-04 11:10:22 +00:00
|
|
|
}
|
1999-04-29 04:37:57 +00:00
|
|
|
|
2001-10-19 01:38:10 +00:00
|
|
|
/*
|
|
|
|
* Device private ioctl handler
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
linux_ioctl_private(struct thread *td, struct linux_ioctl_args *args)
|
|
|
|
{
|
Change the cap_rights_t type from uint64_t to a structure that we can extend
in the future in a backward compatible (API and ABI) way.
The cap_rights_t represents capability rights. We used to use one bit to
represent one right, but we are running out of spare bits. Currently the new
structure provides place for 114 rights (so 50 more than the previous
cap_rights_t), but it is possible to grow the structure to hold at least 285
rights, although we can make it even larger if 285 rights won't be enough.
The structure definition looks like this:
struct cap_rights {
uint64_t cr_rights[CAP_RIGHTS_VERSION + 2];
};
The initial CAP_RIGHTS_VERSION is 0.
The top two bits in the first element of the cr_rights[] array contain total
number of elements in the array - 2. This means if those two bits are equal to
0, we have 2 array elements.
The top two bits in all remaining array elements should be 0.
The next five bits in all array elements contain array index. Only one bit is
used and bit position in this five-bits range defines array index. This means
there can be at most five array elements in the future.
To define new right the CAPRIGHT() macro must be used. The macro takes two
arguments - an array index and a bit to set, eg.
#define CAP_PDKILL CAPRIGHT(1, 0x0000000000000800ULL)
We still support aliases that combine few rights, but the rights have to belong
to the same array element, eg:
#define CAP_LOOKUP CAPRIGHT(0, 0x0000000000000400ULL)
#define CAP_FCHMOD CAPRIGHT(0, 0x0000000000002000ULL)
#define CAP_FCHMODAT (CAP_FCHMOD | CAP_LOOKUP)
There is new API to manage the new cap_rights_t structure:
cap_rights_t *cap_rights_init(cap_rights_t *rights, ...);
void cap_rights_set(cap_rights_t *rights, ...);
void cap_rights_clear(cap_rights_t *rights, ...);
bool cap_rights_is_set(const cap_rights_t *rights, ...);
bool cap_rights_is_valid(const cap_rights_t *rights);
void cap_rights_merge(cap_rights_t *dst, const cap_rights_t *src);
void cap_rights_remove(cap_rights_t *dst, const cap_rights_t *src);
bool cap_rights_contains(const cap_rights_t *big, const cap_rights_t *little);
Capability rights to the cap_rights_init(), cap_rights_set(),
cap_rights_clear() and cap_rights_is_set() functions are provided by
separating them with commas, eg:
cap_rights_t rights;
cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_FSTAT);
There is no need to terminate the list of rights, as those functions are
actually macros that take care of the termination, eg:
#define cap_rights_set(rights, ...) \
__cap_rights_set((rights), __VA_ARGS__, 0ULL)
void __cap_rights_set(cap_rights_t *rights, ...);
Thanks to using one bit as an array index we can assert in those functions that
there are no two rights belonging to different array elements provided
together. For example this is illegal and will be detected, because CAP_LOOKUP
belongs to element 0 and CAP_PDKILL to element 1:
cap_rights_init(&rights, CAP_LOOKUP | CAP_PDKILL);
Providing several rights that belongs to the same array's element this way is
correct, but is not advised. It should only be used for aliases definition.
This commit also breaks compatibility with some existing Capsicum system calls,
but I see no other way to do that. This should be fine as Capsicum is still
experimental and this change is not going to 9.x.
Sponsored by: The FreeBSD Foundation
2013-09-05 00:09:56 +00:00
|
|
|
cap_rights_t rights;
|
2001-10-19 01:38:10 +00:00
|
|
|
struct file *fp;
|
2001-11-19 15:43:50 +00:00
|
|
|
int error, type;
|
2001-10-19 01:38:10 +00:00
|
|
|
|
Change the cap_rights_t type from uint64_t to a structure that we can extend
in the future in a backward compatible (API and ABI) way.
The cap_rights_t represents capability rights. We used to use one bit to
represent one right, but we are running out of spare bits. Currently the new
structure provides place for 114 rights (so 50 more than the previous
cap_rights_t), but it is possible to grow the structure to hold at least 285
rights, although we can make it even larger if 285 rights won't be enough.
The structure definition looks like this:
struct cap_rights {
uint64_t cr_rights[CAP_RIGHTS_VERSION + 2];
};
The initial CAP_RIGHTS_VERSION is 0.
The top two bits in the first element of the cr_rights[] array contain total
number of elements in the array - 2. This means if those two bits are equal to
0, we have 2 array elements.
The top two bits in all remaining array elements should be 0.
The next five bits in all array elements contain array index. Only one bit is
used and bit position in this five-bits range defines array index. This means
there can be at most five array elements in the future.
To define new right the CAPRIGHT() macro must be used. The macro takes two
arguments - an array index and a bit to set, eg.
#define CAP_PDKILL CAPRIGHT(1, 0x0000000000000800ULL)
We still support aliases that combine few rights, but the rights have to belong
to the same array element, eg:
#define CAP_LOOKUP CAPRIGHT(0, 0x0000000000000400ULL)
#define CAP_FCHMOD CAPRIGHT(0, 0x0000000000002000ULL)
#define CAP_FCHMODAT (CAP_FCHMOD | CAP_LOOKUP)
There is new API to manage the new cap_rights_t structure:
cap_rights_t *cap_rights_init(cap_rights_t *rights, ...);
void cap_rights_set(cap_rights_t *rights, ...);
void cap_rights_clear(cap_rights_t *rights, ...);
bool cap_rights_is_set(const cap_rights_t *rights, ...);
bool cap_rights_is_valid(const cap_rights_t *rights);
void cap_rights_merge(cap_rights_t *dst, const cap_rights_t *src);
void cap_rights_remove(cap_rights_t *dst, const cap_rights_t *src);
bool cap_rights_contains(const cap_rights_t *big, const cap_rights_t *little);
Capability rights to the cap_rights_init(), cap_rights_set(),
cap_rights_clear() and cap_rights_is_set() functions are provided by
separating them with commas, eg:
cap_rights_t rights;
cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_FSTAT);
There is no need to terminate the list of rights, as those functions are
actually macros that take care of the termination, eg:
#define cap_rights_set(rights, ...) \
__cap_rights_set((rights), __VA_ARGS__, 0ULL)
void __cap_rights_set(cap_rights_t *rights, ...);
Thanks to using one bit as an array index we can assert in those functions that
there are no two rights belonging to different array elements provided
together. For example this is illegal and will be detected, because CAP_LOOKUP
belongs to element 0 and CAP_PDKILL to element 1:
cap_rights_init(&rights, CAP_LOOKUP | CAP_PDKILL);
Providing several rights that belongs to the same array's element this way is
correct, but is not advised. It should only be used for aliases definition.
This commit also breaks compatibility with some existing Capsicum system calls,
but I see no other way to do that. This should be fine as Capsicum is still
experimental and this change is not going to 9.x.
Sponsored by: The FreeBSD Foundation
2013-09-05 00:09:56 +00:00
|
|
|
error = fget(td, args->fd, cap_rights_init(&rights, CAP_IOCTL), &fp);
|
|
|
|
if (error != 0)
|
2001-11-19 15:43:50 +00:00
|
|
|
return (error);
|
|
|
|
type = fp->f_type;
|
|
|
|
fdrop(fp, td);
|
2001-10-19 01:38:10 +00:00
|
|
|
if (type == DTYPE_SOCKET)
|
|
|
|
return (linux_ioctl_socket(td, args));
|
2001-11-19 15:43:50 +00:00
|
|
|
return (ENOIOCTL);
|
|
|
|
}
|
|
|
|
|
2003-04-24 23:36:35 +00:00
|
|
|
/*
|
|
|
|
* DRM ioctl handler (sys/dev/drm)
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
linux_ioctl_drm(struct thread *td, struct linux_ioctl_args *args)
|
|
|
|
{
|
|
|
|
args->cmd = SETDIR(args->cmd);
|
2018-03-12 15:35:24 +00:00
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
2003-04-24 23:36:35 +00:00
|
|
|
}
|
|
|
|
|
2014-06-02 19:53:53 +00:00
|
|
|
#ifdef COMPAT_LINUX32
|
|
|
|
#define CP(src,dst,fld) do { (dst).fld = (src).fld; } while (0)
|
|
|
|
#define PTRIN_CP(src,dst,fld) \
|
|
|
|
do { (dst).fld = PTRIN((src).fld); } while (0)
|
|
|
|
#define PTROUT_CP(src,dst,fld) \
|
|
|
|
do { (dst).fld = PTROUT((src).fld); } while (0)
|
|
|
|
|
2007-04-07 19:40:58 +00:00
|
|
|
static int
|
2014-06-02 19:53:53 +00:00
|
|
|
linux_ioctl_sg_io(struct thread *td, struct linux_ioctl_args *args)
|
2007-04-07 19:40:58 +00:00
|
|
|
{
|
2014-06-02 19:53:53 +00:00
|
|
|
struct sg_io_hdr io;
|
|
|
|
struct sg_io_hdr32 io32;
|
Change the cap_rights_t type from uint64_t to a structure that we can extend
in the future in a backward compatible (API and ABI) way.
The cap_rights_t represents capability rights. We used to use one bit to
represent one right, but we are running out of spare bits. Currently the new
structure provides place for 114 rights (so 50 more than the previous
cap_rights_t), but it is possible to grow the structure to hold at least 285
rights, although we can make it even larger if 285 rights won't be enough.
The structure definition looks like this:
struct cap_rights {
uint64_t cr_rights[CAP_RIGHTS_VERSION + 2];
};
The initial CAP_RIGHTS_VERSION is 0.
The top two bits in the first element of the cr_rights[] array contain total
number of elements in the array - 2. This means if those two bits are equal to
0, we have 2 array elements.
The top two bits in all remaining array elements should be 0.
The next five bits in all array elements contain array index. Only one bit is
used and bit position in this five-bits range defines array index. This means
there can be at most five array elements in the future.
To define new right the CAPRIGHT() macro must be used. The macro takes two
arguments - an array index and a bit to set, eg.
#define CAP_PDKILL CAPRIGHT(1, 0x0000000000000800ULL)
We still support aliases that combine few rights, but the rights have to belong
to the same array element, eg:
#define CAP_LOOKUP CAPRIGHT(0, 0x0000000000000400ULL)
#define CAP_FCHMOD CAPRIGHT(0, 0x0000000000002000ULL)
#define CAP_FCHMODAT (CAP_FCHMOD | CAP_LOOKUP)
There is new API to manage the new cap_rights_t structure:
cap_rights_t *cap_rights_init(cap_rights_t *rights, ...);
void cap_rights_set(cap_rights_t *rights, ...);
void cap_rights_clear(cap_rights_t *rights, ...);
bool cap_rights_is_set(const cap_rights_t *rights, ...);
bool cap_rights_is_valid(const cap_rights_t *rights);
void cap_rights_merge(cap_rights_t *dst, const cap_rights_t *src);
void cap_rights_remove(cap_rights_t *dst, const cap_rights_t *src);
bool cap_rights_contains(const cap_rights_t *big, const cap_rights_t *little);
Capability rights to the cap_rights_init(), cap_rights_set(),
cap_rights_clear() and cap_rights_is_set() functions are provided by
separating them with commas, eg:
cap_rights_t rights;
cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_FSTAT);
There is no need to terminate the list of rights, as those functions are
actually macros that take care of the termination, eg:
#define cap_rights_set(rights, ...) \
__cap_rights_set((rights), __VA_ARGS__, 0ULL)
void __cap_rights_set(cap_rights_t *rights, ...);
Thanks to using one bit as an array index we can assert in those functions that
there are no two rights belonging to different array elements provided
together. For example this is illegal and will be detected, because CAP_LOOKUP
belongs to element 0 and CAP_PDKILL to element 1:
cap_rights_init(&rights, CAP_LOOKUP | CAP_PDKILL);
Providing several rights that belongs to the same array's element this way is
correct, but is not advised. It should only be used for aliases definition.
This commit also breaks compatibility with some existing Capsicum system calls,
but I see no other way to do that. This should be fine as Capsicum is still
experimental and this change is not going to 9.x.
Sponsored by: The FreeBSD Foundation
2013-09-05 00:09:56 +00:00
|
|
|
cap_rights_t rights;
|
2007-04-07 19:40:58 +00:00
|
|
|
struct file *fp;
|
|
|
|
int error;
|
|
|
|
|
Change the cap_rights_t type from uint64_t to a structure that we can extend
in the future in a backward compatible (API and ABI) way.
The cap_rights_t represents capability rights. We used to use one bit to
represent one right, but we are running out of spare bits. Currently the new
structure provides place for 114 rights (so 50 more than the previous
cap_rights_t), but it is possible to grow the structure to hold at least 285
rights, although we can make it even larger if 285 rights won't be enough.
The structure definition looks like this:
struct cap_rights {
uint64_t cr_rights[CAP_RIGHTS_VERSION + 2];
};
The initial CAP_RIGHTS_VERSION is 0.
The top two bits in the first element of the cr_rights[] array contain total
number of elements in the array - 2. This means if those two bits are equal to
0, we have 2 array elements.
The top two bits in all remaining array elements should be 0.
The next five bits in all array elements contain array index. Only one bit is
used and bit position in this five-bits range defines array index. This means
there can be at most five array elements in the future.
To define new right the CAPRIGHT() macro must be used. The macro takes two
arguments - an array index and a bit to set, eg.
#define CAP_PDKILL CAPRIGHT(1, 0x0000000000000800ULL)
We still support aliases that combine few rights, but the rights have to belong
to the same array element, eg:
#define CAP_LOOKUP CAPRIGHT(0, 0x0000000000000400ULL)
#define CAP_FCHMOD CAPRIGHT(0, 0x0000000000002000ULL)
#define CAP_FCHMODAT (CAP_FCHMOD | CAP_LOOKUP)
There is new API to manage the new cap_rights_t structure:
cap_rights_t *cap_rights_init(cap_rights_t *rights, ...);
void cap_rights_set(cap_rights_t *rights, ...);
void cap_rights_clear(cap_rights_t *rights, ...);
bool cap_rights_is_set(const cap_rights_t *rights, ...);
bool cap_rights_is_valid(const cap_rights_t *rights);
void cap_rights_merge(cap_rights_t *dst, const cap_rights_t *src);
void cap_rights_remove(cap_rights_t *dst, const cap_rights_t *src);
bool cap_rights_contains(const cap_rights_t *big, const cap_rights_t *little);
Capability rights to the cap_rights_init(), cap_rights_set(),
cap_rights_clear() and cap_rights_is_set() functions are provided by
separating them with commas, eg:
cap_rights_t rights;
cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_FSTAT);
There is no need to terminate the list of rights, as those functions are
actually macros that take care of the termination, eg:
#define cap_rights_set(rights, ...) \
__cap_rights_set((rights), __VA_ARGS__, 0ULL)
void __cap_rights_set(cap_rights_t *rights, ...);
Thanks to using one bit as an array index we can assert in those functions that
there are no two rights belonging to different array elements provided
together. For example this is illegal and will be detected, because CAP_LOOKUP
belongs to element 0 and CAP_PDKILL to element 1:
cap_rights_init(&rights, CAP_LOOKUP | CAP_PDKILL);
Providing several rights that belongs to the same array's element this way is
correct, but is not advised. It should only be used for aliases definition.
This commit also breaks compatibility with some existing Capsicum system calls,
but I see no other way to do that. This should be fine as Capsicum is still
experimental and this change is not going to 9.x.
Sponsored by: The FreeBSD Foundation
2013-09-05 00:09:56 +00:00
|
|
|
error = fget(td, args->fd, cap_rights_init(&rights, CAP_IOCTL), &fp);
|
|
|
|
if (error != 0) {
|
2007-04-07 19:40:58 +00:00
|
|
|
printf("sg_linux_ioctl: fget returned %d\n", error);
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
2014-06-02 19:53:53 +00:00
|
|
|
if ((error = copyin((void *)args->arg, &io32, sizeof(io32))) != 0)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
CP(io32, io, interface_id);
|
|
|
|
CP(io32, io, dxfer_direction);
|
|
|
|
CP(io32, io, cmd_len);
|
|
|
|
CP(io32, io, mx_sb_len);
|
|
|
|
CP(io32, io, iovec_count);
|
|
|
|
CP(io32, io, dxfer_len);
|
|
|
|
PTRIN_CP(io32, io, dxferp);
|
|
|
|
PTRIN_CP(io32, io, cmdp);
|
|
|
|
PTRIN_CP(io32, io, sbp);
|
|
|
|
CP(io32, io, timeout);
|
|
|
|
CP(io32, io, flags);
|
|
|
|
CP(io32, io, pack_id);
|
|
|
|
PTRIN_CP(io32, io, usr_ptr);
|
|
|
|
CP(io32, io, status);
|
|
|
|
CP(io32, io, masked_status);
|
|
|
|
CP(io32, io, msg_status);
|
|
|
|
CP(io32, io, sb_len_wr);
|
|
|
|
CP(io32, io, host_status);
|
|
|
|
CP(io32, io, driver_status);
|
|
|
|
CP(io32, io, resid);
|
|
|
|
CP(io32, io, duration);
|
|
|
|
CP(io32, io, info);
|
|
|
|
|
|
|
|
if ((error = fo_ioctl(fp, SG_IO, (caddr_t)&io, td->td_ucred, td)) != 0)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
CP(io, io32, interface_id);
|
|
|
|
CP(io, io32, dxfer_direction);
|
|
|
|
CP(io, io32, cmd_len);
|
|
|
|
CP(io, io32, mx_sb_len);
|
|
|
|
CP(io, io32, iovec_count);
|
|
|
|
CP(io, io32, dxfer_len);
|
|
|
|
PTROUT_CP(io, io32, dxferp);
|
|
|
|
PTROUT_CP(io, io32, cmdp);
|
|
|
|
PTROUT_CP(io, io32, sbp);
|
|
|
|
CP(io, io32, timeout);
|
|
|
|
CP(io, io32, flags);
|
|
|
|
CP(io, io32, pack_id);
|
|
|
|
PTROUT_CP(io, io32, usr_ptr);
|
|
|
|
CP(io, io32, status);
|
|
|
|
CP(io, io32, masked_status);
|
|
|
|
CP(io, io32, msg_status);
|
|
|
|
CP(io, io32, sb_len_wr);
|
|
|
|
CP(io, io32, host_status);
|
|
|
|
CP(io, io32, driver_status);
|
|
|
|
CP(io, io32, resid);
|
|
|
|
CP(io, io32, duration);
|
|
|
|
CP(io, io32, info);
|
|
|
|
|
|
|
|
error = copyout(&io32, (void *)args->arg, sizeof(io32));
|
|
|
|
|
|
|
|
out:
|
2007-04-07 19:40:58 +00:00
|
|
|
fdrop(fp, td);
|
|
|
|
return (error);
|
|
|
|
}
|
2014-06-02 19:53:53 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
static int
|
|
|
|
linux_ioctl_sg(struct thread *td, struct linux_ioctl_args *args)
|
|
|
|
{
|
|
|
|
|
|
|
|
switch (args->cmd) {
|
|
|
|
case LINUX_SG_GET_VERSION_NUM:
|
|
|
|
args->cmd = SG_GET_VERSION_NUM;
|
|
|
|
break;
|
|
|
|
case LINUX_SG_SET_TIMEOUT:
|
|
|
|
args->cmd = SG_SET_TIMEOUT;
|
|
|
|
break;
|
|
|
|
case LINUX_SG_GET_TIMEOUT:
|
|
|
|
args->cmd = SG_GET_TIMEOUT;
|
|
|
|
break;
|
|
|
|
case LINUX_SG_IO:
|
|
|
|
args->cmd = SG_IO;
|
|
|
|
#ifdef COMPAT_LINUX32
|
|
|
|
return (linux_ioctl_sg_io(td, args));
|
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
case LINUX_SG_GET_RESERVED_SIZE:
|
|
|
|
args->cmd = SG_GET_RESERVED_SIZE;
|
|
|
|
break;
|
|
|
|
case LINUX_SG_GET_SCSI_ID:
|
|
|
|
args->cmd = SG_GET_SCSI_ID;
|
|
|
|
break;
|
2014-06-04 12:05:47 +00:00
|
|
|
case LINUX_SG_GET_SG_TABLESIZE:
|
|
|
|
args->cmd = SG_GET_SG_TABLESIZE;
|
|
|
|
break;
|
2014-06-02 19:53:53 +00:00
|
|
|
default:
|
|
|
|
return (ENODEV);
|
|
|
|
}
|
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
|
|
|
}
|
2007-04-07 19:40:58 +00:00
|
|
|
|
2009-12-04 21:06:54 +00:00
|
|
|
/*
|
|
|
|
* Video4Linux (V4L) ioctl handler
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
linux_to_bsd_v4l_tuner(struct l_video_tuner *lvt, struct video_tuner *vt)
|
|
|
|
{
|
|
|
|
vt->tuner = lvt->tuner;
|
|
|
|
strlcpy(vt->name, lvt->name, LINUX_VIDEO_TUNER_NAME_SIZE);
|
|
|
|
vt->rangelow = lvt->rangelow; /* possible long size conversion */
|
|
|
|
vt->rangehigh = lvt->rangehigh; /* possible long size conversion */
|
|
|
|
vt->flags = lvt->flags;
|
|
|
|
vt->mode = lvt->mode;
|
|
|
|
vt->signal = lvt->signal;
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
bsd_to_linux_v4l_tuner(struct video_tuner *vt, struct l_video_tuner *lvt)
|
|
|
|
{
|
|
|
|
lvt->tuner = vt->tuner;
|
|
|
|
strlcpy(lvt->name, vt->name, LINUX_VIDEO_TUNER_NAME_SIZE);
|
|
|
|
lvt->rangelow = vt->rangelow; /* possible long size conversion */
|
|
|
|
lvt->rangehigh = vt->rangehigh; /* possible long size conversion */
|
|
|
|
lvt->flags = vt->flags;
|
|
|
|
lvt->mode = vt->mode;
|
|
|
|
lvt->signal = vt->signal;
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2010-05-03 14:19:58 +00:00
|
|
|
#ifdef COMPAT_LINUX_V4L_CLIPLIST
|
2009-12-04 21:06:54 +00:00
|
|
|
static int
|
|
|
|
linux_to_bsd_v4l_clip(struct l_video_clip *lvc, struct video_clip *vc)
|
|
|
|
{
|
|
|
|
vc->x = lvc->x;
|
|
|
|
vc->y = lvc->y;
|
|
|
|
vc->width = lvc->width;
|
|
|
|
vc->height = lvc->height;
|
|
|
|
vc->next = PTRIN(lvc->next); /* possible pointer size conversion */
|
|
|
|
return (0);
|
|
|
|
}
|
2010-05-03 14:19:58 +00:00
|
|
|
#endif
|
2009-12-04 21:06:54 +00:00
|
|
|
|
|
|
|
static int
|
|
|
|
linux_to_bsd_v4l_window(struct l_video_window *lvw, struct video_window *vw)
|
|
|
|
{
|
|
|
|
vw->x = lvw->x;
|
|
|
|
vw->y = lvw->y;
|
|
|
|
vw->width = lvw->width;
|
|
|
|
vw->height = lvw->height;
|
|
|
|
vw->chromakey = lvw->chromakey;
|
|
|
|
vw->flags = lvw->flags;
|
|
|
|
vw->clips = PTRIN(lvw->clips); /* possible pointer size conversion */
|
|
|
|
vw->clipcount = lvw->clipcount;
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
bsd_to_linux_v4l_window(struct video_window *vw, struct l_video_window *lvw)
|
|
|
|
{
|
|
|
|
lvw->x = vw->x;
|
|
|
|
lvw->y = vw->y;
|
|
|
|
lvw->width = vw->width;
|
|
|
|
lvw->height = vw->height;
|
|
|
|
lvw->chromakey = vw->chromakey;
|
|
|
|
lvw->flags = vw->flags;
|
|
|
|
lvw->clips = PTROUT(vw->clips); /* possible pointer size conversion */
|
|
|
|
lvw->clipcount = vw->clipcount;
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
linux_to_bsd_v4l_buffer(struct l_video_buffer *lvb, struct video_buffer *vb)
|
|
|
|
{
|
|
|
|
vb->base = PTRIN(lvb->base); /* possible pointer size conversion */
|
|
|
|
vb->height = lvb->height;
|
|
|
|
vb->width = lvb->width;
|
|
|
|
vb->depth = lvb->depth;
|
|
|
|
vb->bytesperline = lvb->bytesperline;
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
bsd_to_linux_v4l_buffer(struct video_buffer *vb, struct l_video_buffer *lvb)
|
|
|
|
{
|
|
|
|
lvb->base = PTROUT(vb->base); /* possible pointer size conversion */
|
|
|
|
lvb->height = vb->height;
|
|
|
|
lvb->width = vb->width;
|
|
|
|
lvb->depth = vb->depth;
|
|
|
|
lvb->bytesperline = vb->bytesperline;
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
linux_to_bsd_v4l_code(struct l_video_code *lvc, struct video_code *vc)
|
|
|
|
{
|
|
|
|
strlcpy(vc->loadwhat, lvc->loadwhat, LINUX_VIDEO_CODE_LOADWHAT_SIZE);
|
|
|
|
vc->datasize = lvc->datasize;
|
|
|
|
vc->data = PTRIN(lvc->data); /* possible pointer size conversion */
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2010-05-03 14:19:58 +00:00
|
|
|
#ifdef COMPAT_LINUX_V4L_CLIPLIST
|
2009-12-04 21:06:54 +00:00
|
|
|
static int
|
2010-01-15 14:58:19 +00:00
|
|
|
linux_v4l_clip_copy(void *lvc, struct video_clip **ppvc)
|
2009-12-04 21:06:54 +00:00
|
|
|
{
|
2010-01-15 14:58:19 +00:00
|
|
|
int error;
|
2009-12-04 21:06:54 +00:00
|
|
|
struct video_clip vclip;
|
|
|
|
struct l_video_clip l_vclip;
|
|
|
|
|
2010-01-15 14:58:19 +00:00
|
|
|
error = copyin(lvc, &l_vclip, sizeof(l_vclip));
|
|
|
|
if (error) return (error);
|
|
|
|
linux_to_bsd_v4l_clip(&l_vclip, &vclip);
|
|
|
|
/* XXX: If there can be no concurrency: s/M_NOWAIT/M_WAITOK/ */
|
|
|
|
if ((*ppvc = malloc(sizeof(**ppvc), M_LINUX, M_NOWAIT)) == NULL)
|
2018-02-22 02:24:17 +00:00
|
|
|
return (ENOMEM); /* XXX: Linux has no ENOMEM here. */
|
2010-03-26 08:42:11 +00:00
|
|
|
memcpy(*ppvc, &vclip, sizeof(vclip));
|
2010-01-15 14:58:19 +00:00
|
|
|
(*ppvc)->next = NULL;
|
2009-12-04 21:06:54 +00:00
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
linux_v4l_cliplist_free(struct video_window *vw)
|
|
|
|
{
|
|
|
|
struct video_clip **ppvc;
|
|
|
|
struct video_clip **ppvc_next;
|
|
|
|
|
|
|
|
for (ppvc = &(vw->clips); *ppvc != NULL; ppvc = ppvc_next) {
|
|
|
|
ppvc_next = &((*ppvc)->next);
|
|
|
|
free(*ppvc, M_LINUX);
|
|
|
|
}
|
2010-03-26 08:42:11 +00:00
|
|
|
vw->clips = NULL;
|
|
|
|
|
2009-12-04 21:06:54 +00:00
|
|
|
return (0);
|
|
|
|
}
|
2010-01-15 14:58:19 +00:00
|
|
|
|
|
|
|
static int
|
|
|
|
linux_v4l_cliplist_copy(struct l_video_window *lvw, struct video_window *vw)
|
|
|
|
{
|
|
|
|
int error;
|
|
|
|
int clipcount;
|
|
|
|
void *plvc;
|
|
|
|
struct video_clip **ppvc;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* XXX: The cliplist is used to pass in a list of clipping
|
|
|
|
* rectangles or, if clipcount == VIDEO_CLIP_BITMAP, a
|
|
|
|
* clipping bitmap. Some Linux apps, however, appear to
|
|
|
|
* leave cliplist and clips uninitialized. In any case,
|
|
|
|
* the cliplist is not used by pwc(4), at the time of
|
|
|
|
* writing, FreeBSD's only V4L driver. When a driver
|
|
|
|
* that uses the cliplist is developed, this code may
|
|
|
|
* need re-examiniation.
|
|
|
|
*/
|
|
|
|
error = 0;
|
|
|
|
clipcount = vw->clipcount;
|
|
|
|
if (clipcount == VIDEO_CLIP_BITMAP) {
|
|
|
|
/*
|
|
|
|
* In this case, the pointer (clips) is overloaded
|
|
|
|
* to be a "void *" to a bitmap, therefore there
|
|
|
|
* is no struct video_clip to copy now.
|
|
|
|
*/
|
|
|
|
} else if (clipcount > 0 && clipcount <= 16384) {
|
|
|
|
/*
|
|
|
|
* Clips points to list of clip rectangles, so
|
|
|
|
* copy the list.
|
|
|
|
*
|
|
|
|
* XXX: Upper limit of 16384 was used here to try to
|
|
|
|
* avoid cases when clipcount and clips pointer
|
|
|
|
* are uninitialized and therefore have high random
|
|
|
|
* values, as is the case in the Linux Skype
|
|
|
|
* application. The value 16384 was chosen as that
|
|
|
|
* is what is used in the Linux stradis(4) MPEG
|
|
|
|
* decoder driver, the only place we found an
|
|
|
|
* example of cliplist use.
|
|
|
|
*/
|
|
|
|
plvc = PTRIN(lvw->clips);
|
2010-05-03 14:19:58 +00:00
|
|
|
vw->clips = NULL;
|
2010-01-15 14:58:19 +00:00
|
|
|
ppvc = &(vw->clips);
|
|
|
|
while (clipcount-- > 0) {
|
2016-04-15 16:21:13 +00:00
|
|
|
if (plvc == NULL) {
|
2010-01-15 14:58:19 +00:00
|
|
|
error = EFAULT;
|
|
|
|
break;
|
2010-05-03 14:19:58 +00:00
|
|
|
} else {
|
|
|
|
error = linux_v4l_clip_copy(plvc, ppvc);
|
|
|
|
if (error) {
|
|
|
|
linux_v4l_cliplist_free(vw);
|
|
|
|
break;
|
|
|
|
}
|
2010-01-15 14:58:19 +00:00
|
|
|
}
|
|
|
|
ppvc = &((*ppvc)->next);
|
2018-02-05 17:29:12 +00:00
|
|
|
plvc = PTRIN(((struct l_video_clip *) plvc)->next);
|
2010-01-15 14:58:19 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* clipcount == 0 or negative (but not VIDEO_CLIP_BITMAP)
|
|
|
|
* Force cliplist to null.
|
|
|
|
*/
|
|
|
|
vw->clipcount = 0;
|
|
|
|
vw->clips = NULL;
|
|
|
|
}
|
|
|
|
return (error);
|
|
|
|
}
|
2010-05-03 14:19:58 +00:00
|
|
|
#endif
|
2009-12-04 21:06:54 +00:00
|
|
|
|
|
|
|
static int
|
|
|
|
linux_ioctl_v4l(struct thread *td, struct linux_ioctl_args *args)
|
|
|
|
{
|
Change the cap_rights_t type from uint64_t to a structure that we can extend
in the future in a backward compatible (API and ABI) way.
The cap_rights_t represents capability rights. We used to use one bit to
represent one right, but we are running out of spare bits. Currently the new
structure provides place for 114 rights (so 50 more than the previous
cap_rights_t), but it is possible to grow the structure to hold at least 285
rights, although we can make it even larger if 285 rights won't be enough.
The structure definition looks like this:
struct cap_rights {
uint64_t cr_rights[CAP_RIGHTS_VERSION + 2];
};
The initial CAP_RIGHTS_VERSION is 0.
The top two bits in the first element of the cr_rights[] array contain total
number of elements in the array - 2. This means if those two bits are equal to
0, we have 2 array elements.
The top two bits in all remaining array elements should be 0.
The next five bits in all array elements contain array index. Only one bit is
used and bit position in this five-bits range defines array index. This means
there can be at most five array elements in the future.
To define new right the CAPRIGHT() macro must be used. The macro takes two
arguments - an array index and a bit to set, eg.
#define CAP_PDKILL CAPRIGHT(1, 0x0000000000000800ULL)
We still support aliases that combine few rights, but the rights have to belong
to the same array element, eg:
#define CAP_LOOKUP CAPRIGHT(0, 0x0000000000000400ULL)
#define CAP_FCHMOD CAPRIGHT(0, 0x0000000000002000ULL)
#define CAP_FCHMODAT (CAP_FCHMOD | CAP_LOOKUP)
There is new API to manage the new cap_rights_t structure:
cap_rights_t *cap_rights_init(cap_rights_t *rights, ...);
void cap_rights_set(cap_rights_t *rights, ...);
void cap_rights_clear(cap_rights_t *rights, ...);
bool cap_rights_is_set(const cap_rights_t *rights, ...);
bool cap_rights_is_valid(const cap_rights_t *rights);
void cap_rights_merge(cap_rights_t *dst, const cap_rights_t *src);
void cap_rights_remove(cap_rights_t *dst, const cap_rights_t *src);
bool cap_rights_contains(const cap_rights_t *big, const cap_rights_t *little);
Capability rights to the cap_rights_init(), cap_rights_set(),
cap_rights_clear() and cap_rights_is_set() functions are provided by
separating them with commas, eg:
cap_rights_t rights;
cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_FSTAT);
There is no need to terminate the list of rights, as those functions are
actually macros that take care of the termination, eg:
#define cap_rights_set(rights, ...) \
__cap_rights_set((rights), __VA_ARGS__, 0ULL)
void __cap_rights_set(cap_rights_t *rights, ...);
Thanks to using one bit as an array index we can assert in those functions that
there are no two rights belonging to different array elements provided
together. For example this is illegal and will be detected, because CAP_LOOKUP
belongs to element 0 and CAP_PDKILL to element 1:
cap_rights_init(&rights, CAP_LOOKUP | CAP_PDKILL);
Providing several rights that belongs to the same array's element this way is
correct, but is not advised. It should only be used for aliases definition.
This commit also breaks compatibility with some existing Capsicum system calls,
but I see no other way to do that. This should be fine as Capsicum is still
experimental and this change is not going to 9.x.
Sponsored by: The FreeBSD Foundation
2013-09-05 00:09:56 +00:00
|
|
|
cap_rights_t rights;
|
2009-12-04 21:06:54 +00:00
|
|
|
struct file *fp;
|
|
|
|
int error;
|
|
|
|
struct video_tuner vtun;
|
|
|
|
struct video_window vwin;
|
|
|
|
struct video_buffer vbuf;
|
|
|
|
struct video_code vcode;
|
|
|
|
struct l_video_tuner l_vtun;
|
|
|
|
struct l_video_window l_vwin;
|
|
|
|
struct l_video_buffer l_vbuf;
|
|
|
|
struct l_video_code l_vcode;
|
|
|
|
|
|
|
|
switch (args->cmd & 0xffff) {
|
|
|
|
case LINUX_VIDIOCGCAP: args->cmd = VIDIOCGCAP; break;
|
|
|
|
case LINUX_VIDIOCGCHAN: args->cmd = VIDIOCGCHAN; break;
|
|
|
|
case LINUX_VIDIOCSCHAN: args->cmd = VIDIOCSCHAN; break;
|
|
|
|
|
|
|
|
case LINUX_VIDIOCGTUNER:
|
Change the cap_rights_t type from uint64_t to a structure that we can extend
in the future in a backward compatible (API and ABI) way.
The cap_rights_t represents capability rights. We used to use one bit to
represent one right, but we are running out of spare bits. Currently the new
structure provides place for 114 rights (so 50 more than the previous
cap_rights_t), but it is possible to grow the structure to hold at least 285
rights, although we can make it even larger if 285 rights won't be enough.
The structure definition looks like this:
struct cap_rights {
uint64_t cr_rights[CAP_RIGHTS_VERSION + 2];
};
The initial CAP_RIGHTS_VERSION is 0.
The top two bits in the first element of the cr_rights[] array contain total
number of elements in the array - 2. This means if those two bits are equal to
0, we have 2 array elements.
The top two bits in all remaining array elements should be 0.
The next five bits in all array elements contain array index. Only one bit is
used and bit position in this five-bits range defines array index. This means
there can be at most five array elements in the future.
To define new right the CAPRIGHT() macro must be used. The macro takes two
arguments - an array index and a bit to set, eg.
#define CAP_PDKILL CAPRIGHT(1, 0x0000000000000800ULL)
We still support aliases that combine few rights, but the rights have to belong
to the same array element, eg:
#define CAP_LOOKUP CAPRIGHT(0, 0x0000000000000400ULL)
#define CAP_FCHMOD CAPRIGHT(0, 0x0000000000002000ULL)
#define CAP_FCHMODAT (CAP_FCHMOD | CAP_LOOKUP)
There is new API to manage the new cap_rights_t structure:
cap_rights_t *cap_rights_init(cap_rights_t *rights, ...);
void cap_rights_set(cap_rights_t *rights, ...);
void cap_rights_clear(cap_rights_t *rights, ...);
bool cap_rights_is_set(const cap_rights_t *rights, ...);
bool cap_rights_is_valid(const cap_rights_t *rights);
void cap_rights_merge(cap_rights_t *dst, const cap_rights_t *src);
void cap_rights_remove(cap_rights_t *dst, const cap_rights_t *src);
bool cap_rights_contains(const cap_rights_t *big, const cap_rights_t *little);
Capability rights to the cap_rights_init(), cap_rights_set(),
cap_rights_clear() and cap_rights_is_set() functions are provided by
separating them with commas, eg:
cap_rights_t rights;
cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_FSTAT);
There is no need to terminate the list of rights, as those functions are
actually macros that take care of the termination, eg:
#define cap_rights_set(rights, ...) \
__cap_rights_set((rights), __VA_ARGS__, 0ULL)
void __cap_rights_set(cap_rights_t *rights, ...);
Thanks to using one bit as an array index we can assert in those functions that
there are no two rights belonging to different array elements provided
together. For example this is illegal and will be detected, because CAP_LOOKUP
belongs to element 0 and CAP_PDKILL to element 1:
cap_rights_init(&rights, CAP_LOOKUP | CAP_PDKILL);
Providing several rights that belongs to the same array's element this way is
correct, but is not advised. It should only be used for aliases definition.
This commit also breaks compatibility with some existing Capsicum system calls,
but I see no other way to do that. This should be fine as Capsicum is still
experimental and this change is not going to 9.x.
Sponsored by: The FreeBSD Foundation
2013-09-05 00:09:56 +00:00
|
|
|
error = fget(td, args->fd,
|
|
|
|
cap_rights_init(&rights, CAP_IOCTL), &fp);
|
|
|
|
if (error != 0)
|
2009-12-04 21:06:54 +00:00
|
|
|
return (error);
|
2010-05-03 14:19:58 +00:00
|
|
|
error = copyin((void *) args->arg, &l_vtun, sizeof(l_vtun));
|
|
|
|
if (error) {
|
|
|
|
fdrop(fp, td);
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
linux_to_bsd_v4l_tuner(&l_vtun, &vtun);
|
2009-12-04 21:06:54 +00:00
|
|
|
error = fo_ioctl(fp, VIDIOCGTUNER, &vtun, td->td_ucred, td);
|
|
|
|
if (!error) {
|
|
|
|
bsd_to_linux_v4l_tuner(&vtun, &l_vtun);
|
|
|
|
error = copyout(&l_vtun, (void *) args->arg,
|
|
|
|
sizeof(l_vtun));
|
|
|
|
}
|
|
|
|
fdrop(fp, td);
|
|
|
|
return (error);
|
|
|
|
|
|
|
|
case LINUX_VIDIOCSTUNER:
|
Change the cap_rights_t type from uint64_t to a structure that we can extend
in the future in a backward compatible (API and ABI) way.
The cap_rights_t represents capability rights. We used to use one bit to
represent one right, but we are running out of spare bits. Currently the new
structure provides place for 114 rights (so 50 more than the previous
cap_rights_t), but it is possible to grow the structure to hold at least 285
rights, although we can make it even larger if 285 rights won't be enough.
The structure definition looks like this:
struct cap_rights {
uint64_t cr_rights[CAP_RIGHTS_VERSION + 2];
};
The initial CAP_RIGHTS_VERSION is 0.
The top two bits in the first element of the cr_rights[] array contain total
number of elements in the array - 2. This means if those two bits are equal to
0, we have 2 array elements.
The top two bits in all remaining array elements should be 0.
The next five bits in all array elements contain array index. Only one bit is
used and bit position in this five-bits range defines array index. This means
there can be at most five array elements in the future.
To define new right the CAPRIGHT() macro must be used. The macro takes two
arguments - an array index and a bit to set, eg.
#define CAP_PDKILL CAPRIGHT(1, 0x0000000000000800ULL)
We still support aliases that combine few rights, but the rights have to belong
to the same array element, eg:
#define CAP_LOOKUP CAPRIGHT(0, 0x0000000000000400ULL)
#define CAP_FCHMOD CAPRIGHT(0, 0x0000000000002000ULL)
#define CAP_FCHMODAT (CAP_FCHMOD | CAP_LOOKUP)
There is new API to manage the new cap_rights_t structure:
cap_rights_t *cap_rights_init(cap_rights_t *rights, ...);
void cap_rights_set(cap_rights_t *rights, ...);
void cap_rights_clear(cap_rights_t *rights, ...);
bool cap_rights_is_set(const cap_rights_t *rights, ...);
bool cap_rights_is_valid(const cap_rights_t *rights);
void cap_rights_merge(cap_rights_t *dst, const cap_rights_t *src);
void cap_rights_remove(cap_rights_t *dst, const cap_rights_t *src);
bool cap_rights_contains(const cap_rights_t *big, const cap_rights_t *little);
Capability rights to the cap_rights_init(), cap_rights_set(),
cap_rights_clear() and cap_rights_is_set() functions are provided by
separating them with commas, eg:
cap_rights_t rights;
cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_FSTAT);
There is no need to terminate the list of rights, as those functions are
actually macros that take care of the termination, eg:
#define cap_rights_set(rights, ...) \
__cap_rights_set((rights), __VA_ARGS__, 0ULL)
void __cap_rights_set(cap_rights_t *rights, ...);
Thanks to using one bit as an array index we can assert in those functions that
there are no two rights belonging to different array elements provided
together. For example this is illegal and will be detected, because CAP_LOOKUP
belongs to element 0 and CAP_PDKILL to element 1:
cap_rights_init(&rights, CAP_LOOKUP | CAP_PDKILL);
Providing several rights that belongs to the same array's element this way is
correct, but is not advised. It should only be used for aliases definition.
This commit also breaks compatibility with some existing Capsicum system calls,
but I see no other way to do that. This should be fine as Capsicum is still
experimental and this change is not going to 9.x.
Sponsored by: The FreeBSD Foundation
2013-09-05 00:09:56 +00:00
|
|
|
error = fget(td, args->fd,
|
|
|
|
cap_rights_init(&rights, CAP_IOCTL), &fp);
|
|
|
|
if (error != 0)
|
2009-12-04 21:06:54 +00:00
|
|
|
return (error);
|
|
|
|
error = copyin((void *) args->arg, &l_vtun, sizeof(l_vtun));
|
|
|
|
if (error) {
|
|
|
|
fdrop(fp, td);
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
linux_to_bsd_v4l_tuner(&l_vtun, &vtun);
|
2010-05-03 14:19:58 +00:00
|
|
|
error = fo_ioctl(fp, VIDIOCSTUNER, &vtun, td->td_ucred, td);
|
2009-12-04 21:06:54 +00:00
|
|
|
fdrop(fp, td);
|
|
|
|
return (error);
|
|
|
|
|
|
|
|
case LINUX_VIDIOCGPICT: args->cmd = VIDIOCGPICT; break;
|
|
|
|
case LINUX_VIDIOCSPICT: args->cmd = VIDIOCSPICT; break;
|
|
|
|
case LINUX_VIDIOCCAPTURE: args->cmd = VIDIOCCAPTURE; break;
|
|
|
|
|
|
|
|
case LINUX_VIDIOCGWIN:
|
Change the cap_rights_t type from uint64_t to a structure that we can extend
in the future in a backward compatible (API and ABI) way.
The cap_rights_t represents capability rights. We used to use one bit to
represent one right, but we are running out of spare bits. Currently the new
structure provides place for 114 rights (so 50 more than the previous
cap_rights_t), but it is possible to grow the structure to hold at least 285
rights, although we can make it even larger if 285 rights won't be enough.
The structure definition looks like this:
struct cap_rights {
uint64_t cr_rights[CAP_RIGHTS_VERSION + 2];
};
The initial CAP_RIGHTS_VERSION is 0.
The top two bits in the first element of the cr_rights[] array contain total
number of elements in the array - 2. This means if those two bits are equal to
0, we have 2 array elements.
The top two bits in all remaining array elements should be 0.
The next five bits in all array elements contain array index. Only one bit is
used and bit position in this five-bits range defines array index. This means
there can be at most five array elements in the future.
To define new right the CAPRIGHT() macro must be used. The macro takes two
arguments - an array index and a bit to set, eg.
#define CAP_PDKILL CAPRIGHT(1, 0x0000000000000800ULL)
We still support aliases that combine few rights, but the rights have to belong
to the same array element, eg:
#define CAP_LOOKUP CAPRIGHT(0, 0x0000000000000400ULL)
#define CAP_FCHMOD CAPRIGHT(0, 0x0000000000002000ULL)
#define CAP_FCHMODAT (CAP_FCHMOD | CAP_LOOKUP)
There is new API to manage the new cap_rights_t structure:
cap_rights_t *cap_rights_init(cap_rights_t *rights, ...);
void cap_rights_set(cap_rights_t *rights, ...);
void cap_rights_clear(cap_rights_t *rights, ...);
bool cap_rights_is_set(const cap_rights_t *rights, ...);
bool cap_rights_is_valid(const cap_rights_t *rights);
void cap_rights_merge(cap_rights_t *dst, const cap_rights_t *src);
void cap_rights_remove(cap_rights_t *dst, const cap_rights_t *src);
bool cap_rights_contains(const cap_rights_t *big, const cap_rights_t *little);
Capability rights to the cap_rights_init(), cap_rights_set(),
cap_rights_clear() and cap_rights_is_set() functions are provided by
separating them with commas, eg:
cap_rights_t rights;
cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_FSTAT);
There is no need to terminate the list of rights, as those functions are
actually macros that take care of the termination, eg:
#define cap_rights_set(rights, ...) \
__cap_rights_set((rights), __VA_ARGS__, 0ULL)
void __cap_rights_set(cap_rights_t *rights, ...);
Thanks to using one bit as an array index we can assert in those functions that
there are no two rights belonging to different array elements provided
together. For example this is illegal and will be detected, because CAP_LOOKUP
belongs to element 0 and CAP_PDKILL to element 1:
cap_rights_init(&rights, CAP_LOOKUP | CAP_PDKILL);
Providing several rights that belongs to the same array's element this way is
correct, but is not advised. It should only be used for aliases definition.
This commit also breaks compatibility with some existing Capsicum system calls,
but I see no other way to do that. This should be fine as Capsicum is still
experimental and this change is not going to 9.x.
Sponsored by: The FreeBSD Foundation
2013-09-05 00:09:56 +00:00
|
|
|
error = fget(td, args->fd,
|
|
|
|
cap_rights_init(&rights, CAP_IOCTL), &fp);
|
|
|
|
if (error != 0)
|
2009-12-04 21:06:54 +00:00
|
|
|
return (error);
|
|
|
|
error = fo_ioctl(fp, VIDIOCGWIN, &vwin, td->td_ucred, td);
|
|
|
|
if (!error) {
|
|
|
|
bsd_to_linux_v4l_window(&vwin, &l_vwin);
|
|
|
|
error = copyout(&l_vwin, (void *) args->arg,
|
|
|
|
sizeof(l_vwin));
|
|
|
|
}
|
|
|
|
fdrop(fp, td);
|
|
|
|
return (error);
|
|
|
|
|
|
|
|
case LINUX_VIDIOCSWIN:
|
Change the cap_rights_t type from uint64_t to a structure that we can extend
in the future in a backward compatible (API and ABI) way.
The cap_rights_t represents capability rights. We used to use one bit to
represent one right, but we are running out of spare bits. Currently the new
structure provides place for 114 rights (so 50 more than the previous
cap_rights_t), but it is possible to grow the structure to hold at least 285
rights, although we can make it even larger if 285 rights won't be enough.
The structure definition looks like this:
struct cap_rights {
uint64_t cr_rights[CAP_RIGHTS_VERSION + 2];
};
The initial CAP_RIGHTS_VERSION is 0.
The top two bits in the first element of the cr_rights[] array contain total
number of elements in the array - 2. This means if those two bits are equal to
0, we have 2 array elements.
The top two bits in all remaining array elements should be 0.
The next five bits in all array elements contain array index. Only one bit is
used and bit position in this five-bits range defines array index. This means
there can be at most five array elements in the future.
To define new right the CAPRIGHT() macro must be used. The macro takes two
arguments - an array index and a bit to set, eg.
#define CAP_PDKILL CAPRIGHT(1, 0x0000000000000800ULL)
We still support aliases that combine few rights, but the rights have to belong
to the same array element, eg:
#define CAP_LOOKUP CAPRIGHT(0, 0x0000000000000400ULL)
#define CAP_FCHMOD CAPRIGHT(0, 0x0000000000002000ULL)
#define CAP_FCHMODAT (CAP_FCHMOD | CAP_LOOKUP)
There is new API to manage the new cap_rights_t structure:
cap_rights_t *cap_rights_init(cap_rights_t *rights, ...);
void cap_rights_set(cap_rights_t *rights, ...);
void cap_rights_clear(cap_rights_t *rights, ...);
bool cap_rights_is_set(const cap_rights_t *rights, ...);
bool cap_rights_is_valid(const cap_rights_t *rights);
void cap_rights_merge(cap_rights_t *dst, const cap_rights_t *src);
void cap_rights_remove(cap_rights_t *dst, const cap_rights_t *src);
bool cap_rights_contains(const cap_rights_t *big, const cap_rights_t *little);
Capability rights to the cap_rights_init(), cap_rights_set(),
cap_rights_clear() and cap_rights_is_set() functions are provided by
separating them with commas, eg:
cap_rights_t rights;
cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_FSTAT);
There is no need to terminate the list of rights, as those functions are
actually macros that take care of the termination, eg:
#define cap_rights_set(rights, ...) \
__cap_rights_set((rights), __VA_ARGS__, 0ULL)
void __cap_rights_set(cap_rights_t *rights, ...);
Thanks to using one bit as an array index we can assert in those functions that
there are no two rights belonging to different array elements provided
together. For example this is illegal and will be detected, because CAP_LOOKUP
belongs to element 0 and CAP_PDKILL to element 1:
cap_rights_init(&rights, CAP_LOOKUP | CAP_PDKILL);
Providing several rights that belongs to the same array's element this way is
correct, but is not advised. It should only be used for aliases definition.
This commit also breaks compatibility with some existing Capsicum system calls,
but I see no other way to do that. This should be fine as Capsicum is still
experimental and this change is not going to 9.x.
Sponsored by: The FreeBSD Foundation
2013-09-05 00:09:56 +00:00
|
|
|
error = fget(td, args->fd,
|
|
|
|
cap_rights_init(&rights, CAP_IOCTL), &fp);
|
|
|
|
if (error != 0)
|
2009-12-04 21:06:54 +00:00
|
|
|
return (error);
|
|
|
|
error = copyin((void *) args->arg, &l_vwin, sizeof(l_vwin));
|
|
|
|
if (error) {
|
|
|
|
fdrop(fp, td);
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
linux_to_bsd_v4l_window(&l_vwin, &vwin);
|
2010-05-03 14:19:58 +00:00
|
|
|
#ifdef COMPAT_LINUX_V4L_CLIPLIST
|
2009-12-04 21:06:54 +00:00
|
|
|
error = linux_v4l_cliplist_copy(&l_vwin, &vwin);
|
2010-01-15 14:58:19 +00:00
|
|
|
if (error) {
|
|
|
|
fdrop(fp, td);
|
|
|
|
return (error);
|
|
|
|
}
|
2010-05-03 14:19:58 +00:00
|
|
|
#endif
|
2010-01-15 14:58:19 +00:00
|
|
|
error = fo_ioctl(fp, VIDIOCSWIN, &vwin, td->td_ucred, td);
|
2009-12-04 21:06:54 +00:00
|
|
|
fdrop(fp, td);
|
2010-05-03 14:19:58 +00:00
|
|
|
#ifdef COMPAT_LINUX_V4L_CLIPLIST
|
2009-12-04 21:06:54 +00:00
|
|
|
linux_v4l_cliplist_free(&vwin);
|
2010-05-03 14:19:58 +00:00
|
|
|
#endif
|
2009-12-04 21:06:54 +00:00
|
|
|
return (error);
|
|
|
|
|
|
|
|
case LINUX_VIDIOCGFBUF:
|
Change the cap_rights_t type from uint64_t to a structure that we can extend
in the future in a backward compatible (API and ABI) way.
The cap_rights_t represents capability rights. We used to use one bit to
represent one right, but we are running out of spare bits. Currently the new
structure provides place for 114 rights (so 50 more than the previous
cap_rights_t), but it is possible to grow the structure to hold at least 285
rights, although we can make it even larger if 285 rights won't be enough.
The structure definition looks like this:
struct cap_rights {
uint64_t cr_rights[CAP_RIGHTS_VERSION + 2];
};
The initial CAP_RIGHTS_VERSION is 0.
The top two bits in the first element of the cr_rights[] array contain total
number of elements in the array - 2. This means if those two bits are equal to
0, we have 2 array elements.
The top two bits in all remaining array elements should be 0.
The next five bits in all array elements contain array index. Only one bit is
used and bit position in this five-bits range defines array index. This means
there can be at most five array elements in the future.
To define new right the CAPRIGHT() macro must be used. The macro takes two
arguments - an array index and a bit to set, eg.
#define CAP_PDKILL CAPRIGHT(1, 0x0000000000000800ULL)
We still support aliases that combine few rights, but the rights have to belong
to the same array element, eg:
#define CAP_LOOKUP CAPRIGHT(0, 0x0000000000000400ULL)
#define CAP_FCHMOD CAPRIGHT(0, 0x0000000000002000ULL)
#define CAP_FCHMODAT (CAP_FCHMOD | CAP_LOOKUP)
There is new API to manage the new cap_rights_t structure:
cap_rights_t *cap_rights_init(cap_rights_t *rights, ...);
void cap_rights_set(cap_rights_t *rights, ...);
void cap_rights_clear(cap_rights_t *rights, ...);
bool cap_rights_is_set(const cap_rights_t *rights, ...);
bool cap_rights_is_valid(const cap_rights_t *rights);
void cap_rights_merge(cap_rights_t *dst, const cap_rights_t *src);
void cap_rights_remove(cap_rights_t *dst, const cap_rights_t *src);
bool cap_rights_contains(const cap_rights_t *big, const cap_rights_t *little);
Capability rights to the cap_rights_init(), cap_rights_set(),
cap_rights_clear() and cap_rights_is_set() functions are provided by
separating them with commas, eg:
cap_rights_t rights;
cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_FSTAT);
There is no need to terminate the list of rights, as those functions are
actually macros that take care of the termination, eg:
#define cap_rights_set(rights, ...) \
__cap_rights_set((rights), __VA_ARGS__, 0ULL)
void __cap_rights_set(cap_rights_t *rights, ...);
Thanks to using one bit as an array index we can assert in those functions that
there are no two rights belonging to different array elements provided
together. For example this is illegal and will be detected, because CAP_LOOKUP
belongs to element 0 and CAP_PDKILL to element 1:
cap_rights_init(&rights, CAP_LOOKUP | CAP_PDKILL);
Providing several rights that belongs to the same array's element this way is
correct, but is not advised. It should only be used for aliases definition.
This commit also breaks compatibility with some existing Capsicum system calls,
but I see no other way to do that. This should be fine as Capsicum is still
experimental and this change is not going to 9.x.
Sponsored by: The FreeBSD Foundation
2013-09-05 00:09:56 +00:00
|
|
|
error = fget(td, args->fd,
|
|
|
|
cap_rights_init(&rights, CAP_IOCTL), &fp);
|
|
|
|
if (error != 0)
|
2009-12-04 21:06:54 +00:00
|
|
|
return (error);
|
|
|
|
error = fo_ioctl(fp, VIDIOCGFBUF, &vbuf, td->td_ucred, td);
|
|
|
|
if (!error) {
|
|
|
|
bsd_to_linux_v4l_buffer(&vbuf, &l_vbuf);
|
|
|
|
error = copyout(&l_vbuf, (void *) args->arg,
|
|
|
|
sizeof(l_vbuf));
|
|
|
|
}
|
|
|
|
fdrop(fp, td);
|
|
|
|
return (error);
|
|
|
|
|
|
|
|
case LINUX_VIDIOCSFBUF:
|
Change the cap_rights_t type from uint64_t to a structure that we can extend
in the future in a backward compatible (API and ABI) way.
The cap_rights_t represents capability rights. We used to use one bit to
represent one right, but we are running out of spare bits. Currently the new
structure provides place for 114 rights (so 50 more than the previous
cap_rights_t), but it is possible to grow the structure to hold at least 285
rights, although we can make it even larger if 285 rights won't be enough.
The structure definition looks like this:
struct cap_rights {
uint64_t cr_rights[CAP_RIGHTS_VERSION + 2];
};
The initial CAP_RIGHTS_VERSION is 0.
The top two bits in the first element of the cr_rights[] array contain total
number of elements in the array - 2. This means if those two bits are equal to
0, we have 2 array elements.
The top two bits in all remaining array elements should be 0.
The next five bits in all array elements contain array index. Only one bit is
used and bit position in this five-bits range defines array index. This means
there can be at most five array elements in the future.
To define new right the CAPRIGHT() macro must be used. The macro takes two
arguments - an array index and a bit to set, eg.
#define CAP_PDKILL CAPRIGHT(1, 0x0000000000000800ULL)
We still support aliases that combine few rights, but the rights have to belong
to the same array element, eg:
#define CAP_LOOKUP CAPRIGHT(0, 0x0000000000000400ULL)
#define CAP_FCHMOD CAPRIGHT(0, 0x0000000000002000ULL)
#define CAP_FCHMODAT (CAP_FCHMOD | CAP_LOOKUP)
There is new API to manage the new cap_rights_t structure:
cap_rights_t *cap_rights_init(cap_rights_t *rights, ...);
void cap_rights_set(cap_rights_t *rights, ...);
void cap_rights_clear(cap_rights_t *rights, ...);
bool cap_rights_is_set(const cap_rights_t *rights, ...);
bool cap_rights_is_valid(const cap_rights_t *rights);
void cap_rights_merge(cap_rights_t *dst, const cap_rights_t *src);
void cap_rights_remove(cap_rights_t *dst, const cap_rights_t *src);
bool cap_rights_contains(const cap_rights_t *big, const cap_rights_t *little);
Capability rights to the cap_rights_init(), cap_rights_set(),
cap_rights_clear() and cap_rights_is_set() functions are provided by
separating them with commas, eg:
cap_rights_t rights;
cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_FSTAT);
There is no need to terminate the list of rights, as those functions are
actually macros that take care of the termination, eg:
#define cap_rights_set(rights, ...) \
__cap_rights_set((rights), __VA_ARGS__, 0ULL)
void __cap_rights_set(cap_rights_t *rights, ...);
Thanks to using one bit as an array index we can assert in those functions that
there are no two rights belonging to different array elements provided
together. For example this is illegal and will be detected, because CAP_LOOKUP
belongs to element 0 and CAP_PDKILL to element 1:
cap_rights_init(&rights, CAP_LOOKUP | CAP_PDKILL);
Providing several rights that belongs to the same array's element this way is
correct, but is not advised. It should only be used for aliases definition.
This commit also breaks compatibility with some existing Capsicum system calls,
but I see no other way to do that. This should be fine as Capsicum is still
experimental and this change is not going to 9.x.
Sponsored by: The FreeBSD Foundation
2013-09-05 00:09:56 +00:00
|
|
|
error = fget(td, args->fd,
|
|
|
|
cap_rights_init(&rights, CAP_IOCTL), &fp);
|
|
|
|
if (error != 0)
|
2009-12-04 21:06:54 +00:00
|
|
|
return (error);
|
|
|
|
error = copyin((void *) args->arg, &l_vbuf, sizeof(l_vbuf));
|
|
|
|
if (error) {
|
|
|
|
fdrop(fp, td);
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
linux_to_bsd_v4l_buffer(&l_vbuf, &vbuf);
|
|
|
|
error = fo_ioctl(fp, VIDIOCSFBUF, &vbuf, td->td_ucred, td);
|
|
|
|
fdrop(fp, td);
|
|
|
|
return (error);
|
|
|
|
|
|
|
|
case LINUX_VIDIOCKEY: args->cmd = VIDIOCKEY; break;
|
|
|
|
case LINUX_VIDIOCGFREQ: args->cmd = VIDIOCGFREQ; break;
|
|
|
|
case LINUX_VIDIOCSFREQ: args->cmd = VIDIOCSFREQ; break;
|
|
|
|
case LINUX_VIDIOCGAUDIO: args->cmd = VIDIOCGAUDIO; break;
|
|
|
|
case LINUX_VIDIOCSAUDIO: args->cmd = VIDIOCSAUDIO; break;
|
|
|
|
case LINUX_VIDIOCSYNC: args->cmd = VIDIOCSYNC; break;
|
|
|
|
case LINUX_VIDIOCMCAPTURE: args->cmd = VIDIOCMCAPTURE; break;
|
|
|
|
case LINUX_VIDIOCGMBUF: args->cmd = VIDIOCGMBUF; break;
|
|
|
|
case LINUX_VIDIOCGUNIT: args->cmd = VIDIOCGUNIT; break;
|
|
|
|
case LINUX_VIDIOCGCAPTURE: args->cmd = VIDIOCGCAPTURE; break;
|
|
|
|
case LINUX_VIDIOCSCAPTURE: args->cmd = VIDIOCSCAPTURE; break;
|
|
|
|
case LINUX_VIDIOCSPLAYMODE: args->cmd = VIDIOCSPLAYMODE; break;
|
|
|
|
case LINUX_VIDIOCSWRITEMODE: args->cmd = VIDIOCSWRITEMODE; break;
|
|
|
|
case LINUX_VIDIOCGPLAYINFO: args->cmd = VIDIOCGPLAYINFO; break;
|
|
|
|
|
|
|
|
case LINUX_VIDIOCSMICROCODE:
|
Change the cap_rights_t type from uint64_t to a structure that we can extend
in the future in a backward compatible (API and ABI) way.
The cap_rights_t represents capability rights. We used to use one bit to
represent one right, but we are running out of spare bits. Currently the new
structure provides place for 114 rights (so 50 more than the previous
cap_rights_t), but it is possible to grow the structure to hold at least 285
rights, although we can make it even larger if 285 rights won't be enough.
The structure definition looks like this:
struct cap_rights {
uint64_t cr_rights[CAP_RIGHTS_VERSION + 2];
};
The initial CAP_RIGHTS_VERSION is 0.
The top two bits in the first element of the cr_rights[] array contain total
number of elements in the array - 2. This means if those two bits are equal to
0, we have 2 array elements.
The top two bits in all remaining array elements should be 0.
The next five bits in all array elements contain array index. Only one bit is
used and bit position in this five-bits range defines array index. This means
there can be at most five array elements in the future.
To define new right the CAPRIGHT() macro must be used. The macro takes two
arguments - an array index and a bit to set, eg.
#define CAP_PDKILL CAPRIGHT(1, 0x0000000000000800ULL)
We still support aliases that combine few rights, but the rights have to belong
to the same array element, eg:
#define CAP_LOOKUP CAPRIGHT(0, 0x0000000000000400ULL)
#define CAP_FCHMOD CAPRIGHT(0, 0x0000000000002000ULL)
#define CAP_FCHMODAT (CAP_FCHMOD | CAP_LOOKUP)
There is new API to manage the new cap_rights_t structure:
cap_rights_t *cap_rights_init(cap_rights_t *rights, ...);
void cap_rights_set(cap_rights_t *rights, ...);
void cap_rights_clear(cap_rights_t *rights, ...);
bool cap_rights_is_set(const cap_rights_t *rights, ...);
bool cap_rights_is_valid(const cap_rights_t *rights);
void cap_rights_merge(cap_rights_t *dst, const cap_rights_t *src);
void cap_rights_remove(cap_rights_t *dst, const cap_rights_t *src);
bool cap_rights_contains(const cap_rights_t *big, const cap_rights_t *little);
Capability rights to the cap_rights_init(), cap_rights_set(),
cap_rights_clear() and cap_rights_is_set() functions are provided by
separating them with commas, eg:
cap_rights_t rights;
cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_FSTAT);
There is no need to terminate the list of rights, as those functions are
actually macros that take care of the termination, eg:
#define cap_rights_set(rights, ...) \
__cap_rights_set((rights), __VA_ARGS__, 0ULL)
void __cap_rights_set(cap_rights_t *rights, ...);
Thanks to using one bit as an array index we can assert in those functions that
there are no two rights belonging to different array elements provided
together. For example this is illegal and will be detected, because CAP_LOOKUP
belongs to element 0 and CAP_PDKILL to element 1:
cap_rights_init(&rights, CAP_LOOKUP | CAP_PDKILL);
Providing several rights that belongs to the same array's element this way is
correct, but is not advised. It should only be used for aliases definition.
This commit also breaks compatibility with some existing Capsicum system calls,
but I see no other way to do that. This should be fine as Capsicum is still
experimental and this change is not going to 9.x.
Sponsored by: The FreeBSD Foundation
2013-09-05 00:09:56 +00:00
|
|
|
error = fget(td, args->fd,
|
|
|
|
cap_rights_init(&rights, CAP_IOCTL), &fp);
|
|
|
|
if (error != 0)
|
2009-12-04 21:06:54 +00:00
|
|
|
return (error);
|
|
|
|
error = copyin((void *) args->arg, &l_vcode, sizeof(l_vcode));
|
|
|
|
if (error) {
|
|
|
|
fdrop(fp, td);
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
linux_to_bsd_v4l_code(&l_vcode, &vcode);
|
2010-05-03 14:19:58 +00:00
|
|
|
error = fo_ioctl(fp, VIDIOCSMICROCODE, &vcode, td->td_ucred, td);
|
2009-12-04 21:06:54 +00:00
|
|
|
fdrop(fp, td);
|
|
|
|
return (error);
|
|
|
|
|
|
|
|
case LINUX_VIDIOCGVBIFMT: args->cmd = VIDIOCGVBIFMT; break;
|
|
|
|
case LINUX_VIDIOCSVBIFMT: args->cmd = VIDIOCSVBIFMT; break;
|
|
|
|
default: return (ENOIOCTL);
|
|
|
|
}
|
|
|
|
|
2011-09-16 13:58:51 +00:00
|
|
|
error = sys_ioctl(td, (struct ioctl_args *)args);
|
2009-12-04 21:06:54 +00:00
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
2001-11-19 15:43:50 +00:00
|
|
|
/*
|
|
|
|
* Special ioctl handler
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
linux_ioctl_special(struct thread *td, struct linux_ioctl_args *args)
|
|
|
|
{
|
|
|
|
int error;
|
|
|
|
|
|
|
|
switch (args->cmd) {
|
|
|
|
case LINUX_SIOCGIFADDR:
|
|
|
|
args->cmd = SIOCGIFADDR;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = sys_ioctl(td, (struct ioctl_args *)args);
|
2001-11-19 15:43:50 +00:00
|
|
|
break;
|
|
|
|
case LINUX_SIOCSIFADDR:
|
|
|
|
args->cmd = SIOCSIFADDR;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = sys_ioctl(td, (struct ioctl_args *)args);
|
2001-11-19 15:43:50 +00:00
|
|
|
break;
|
|
|
|
case LINUX_SIOCGIFFLAGS:
|
|
|
|
args->cmd = SIOCGIFFLAGS;
|
2011-09-16 13:58:51 +00:00
|
|
|
error = sys_ioctl(td, (struct ioctl_args *)args);
|
2001-11-19 15:43:50 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
error = ENOIOCTL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (error);
|
2001-10-19 01:38:10 +00:00
|
|
|
}
|
|
|
|
|
2011-05-04 09:05:39 +00:00
|
|
|
static int
|
|
|
|
linux_to_bsd_v4l2_standard(struct l_v4l2_standard *lvstd, struct v4l2_standard *vstd)
|
|
|
|
{
|
|
|
|
vstd->index = lvstd->index;
|
|
|
|
vstd->id = lvstd->id;
|
2017-04-13 17:34:51 +00:00
|
|
|
CTASSERT(sizeof(vstd->name) == sizeof(lvstd->name));
|
|
|
|
memcpy(vstd->name, lvstd->name, sizeof(vstd->name));
|
|
|
|
vstd->frameperiod = lvstd->frameperiod;
|
|
|
|
vstd->framelines = lvstd->framelines;
|
|
|
|
CTASSERT(sizeof(vstd->reserved) == sizeof(lvstd->reserved));
|
|
|
|
memcpy(vstd->reserved, lvstd->reserved, sizeof(vstd->reserved));
|
2011-05-04 09:05:39 +00:00
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
bsd_to_linux_v4l2_standard(struct v4l2_standard *vstd, struct l_v4l2_standard *lvstd)
|
|
|
|
{
|
|
|
|
lvstd->index = vstd->index;
|
|
|
|
lvstd->id = vstd->id;
|
2017-04-13 17:34:51 +00:00
|
|
|
CTASSERT(sizeof(vstd->name) == sizeof(lvstd->name));
|
|
|
|
memcpy(lvstd->name, vstd->name, sizeof(lvstd->name));
|
|
|
|
lvstd->frameperiod = vstd->frameperiod;
|
|
|
|
lvstd->framelines = vstd->framelines;
|
|
|
|
CTASSERT(sizeof(vstd->reserved) == sizeof(lvstd->reserved));
|
|
|
|
memcpy(lvstd->reserved, vstd->reserved, sizeof(lvstd->reserved));
|
2011-05-04 09:05:39 +00:00
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
linux_to_bsd_v4l2_buffer(struct l_v4l2_buffer *lvb, struct v4l2_buffer *vb)
|
|
|
|
{
|
|
|
|
vb->index = lvb->index;
|
|
|
|
vb->type = lvb->type;
|
|
|
|
vb->bytesused = lvb->bytesused;
|
|
|
|
vb->flags = lvb->flags;
|
|
|
|
vb->field = lvb->field;
|
|
|
|
vb->timestamp.tv_sec = lvb->timestamp.tv_sec;
|
|
|
|
vb->timestamp.tv_usec = lvb->timestamp.tv_usec;
|
|
|
|
memcpy(&vb->timecode, &lvb->timecode, sizeof (lvb->timecode));
|
|
|
|
vb->sequence = lvb->sequence;
|
|
|
|
vb->memory = lvb->memory;
|
|
|
|
if (lvb->memory == V4L2_MEMORY_USERPTR)
|
|
|
|
/* possible pointer size conversion */
|
|
|
|
vb->m.userptr = (unsigned long)PTRIN(lvb->m.userptr);
|
|
|
|
else
|
|
|
|
vb->m.offset = lvb->m.offset;
|
|
|
|
vb->length = lvb->length;
|
|
|
|
vb->input = lvb->input;
|
|
|
|
vb->reserved = lvb->reserved;
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
bsd_to_linux_v4l2_buffer(struct v4l2_buffer *vb, struct l_v4l2_buffer *lvb)
|
|
|
|
{
|
|
|
|
lvb->index = vb->index;
|
|
|
|
lvb->type = vb->type;
|
|
|
|
lvb->bytesused = vb->bytesused;
|
|
|
|
lvb->flags = vb->flags;
|
|
|
|
lvb->field = vb->field;
|
|
|
|
lvb->timestamp.tv_sec = vb->timestamp.tv_sec;
|
|
|
|
lvb->timestamp.tv_usec = vb->timestamp.tv_usec;
|
|
|
|
memcpy(&lvb->timecode, &vb->timecode, sizeof (vb->timecode));
|
|
|
|
lvb->sequence = vb->sequence;
|
|
|
|
lvb->memory = vb->memory;
|
|
|
|
if (vb->memory == V4L2_MEMORY_USERPTR)
|
|
|
|
/* possible pointer size conversion */
|
|
|
|
lvb->m.userptr = PTROUT(vb->m.userptr);
|
|
|
|
else
|
|
|
|
lvb->m.offset = vb->m.offset;
|
|
|
|
lvb->length = vb->length;
|
|
|
|
lvb->input = vb->input;
|
|
|
|
lvb->reserved = vb->reserved;
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
linux_to_bsd_v4l2_format(struct l_v4l2_format *lvf, struct v4l2_format *vf)
|
|
|
|
{
|
|
|
|
vf->type = lvf->type;
|
|
|
|
if (lvf->type == V4L2_BUF_TYPE_VIDEO_OVERLAY
|
|
|
|
#ifdef V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY
|
|
|
|
|| lvf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY
|
|
|
|
#endif
|
|
|
|
)
|
|
|
|
/*
|
|
|
|
* XXX TODO - needs 32 -> 64 bit conversion:
|
|
|
|
* (unused by webcams?)
|
|
|
|
*/
|
2018-03-12 15:35:24 +00:00
|
|
|
return (EINVAL);
|
2011-05-04 09:05:39 +00:00
|
|
|
memcpy(&vf->fmt, &lvf->fmt, sizeof(vf->fmt));
|
2018-03-12 15:35:24 +00:00
|
|
|
return (0);
|
2011-05-04 09:05:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
bsd_to_linux_v4l2_format(struct v4l2_format *vf, struct l_v4l2_format *lvf)
|
|
|
|
{
|
|
|
|
lvf->type = vf->type;
|
|
|
|
if (vf->type == V4L2_BUF_TYPE_VIDEO_OVERLAY
|
|
|
|
#ifdef V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY
|
|
|
|
|| vf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY
|
|
|
|
#endif
|
|
|
|
)
|
|
|
|
/*
|
|
|
|
* XXX TODO - needs 32 -> 64 bit conversion:
|
|
|
|
* (unused by webcams?)
|
|
|
|
*/
|
2018-03-12 15:35:24 +00:00
|
|
|
return (EINVAL);
|
2011-05-04 09:05:39 +00:00
|
|
|
memcpy(&lvf->fmt, &vf->fmt, sizeof(vf->fmt));
|
2018-03-12 15:35:24 +00:00
|
|
|
return (0);
|
2011-05-04 09:05:39 +00:00
|
|
|
}
|
|
|
|
static int
|
|
|
|
linux_ioctl_v4l2(struct thread *td, struct linux_ioctl_args *args)
|
|
|
|
{
|
Change the cap_rights_t type from uint64_t to a structure that we can extend
in the future in a backward compatible (API and ABI) way.
The cap_rights_t represents capability rights. We used to use one bit to
represent one right, but we are running out of spare bits. Currently the new
structure provides place for 114 rights (so 50 more than the previous
cap_rights_t), but it is possible to grow the structure to hold at least 285
rights, although we can make it even larger if 285 rights won't be enough.
The structure definition looks like this:
struct cap_rights {
uint64_t cr_rights[CAP_RIGHTS_VERSION + 2];
};
The initial CAP_RIGHTS_VERSION is 0.
The top two bits in the first element of the cr_rights[] array contain total
number of elements in the array - 2. This means if those two bits are equal to
0, we have 2 array elements.
The top two bits in all remaining array elements should be 0.
The next five bits in all array elements contain array index. Only one bit is
used and bit position in this five-bits range defines array index. This means
there can be at most five array elements in the future.
To define new right the CAPRIGHT() macro must be used. The macro takes two
arguments - an array index and a bit to set, eg.
#define CAP_PDKILL CAPRIGHT(1, 0x0000000000000800ULL)
We still support aliases that combine few rights, but the rights have to belong
to the same array element, eg:
#define CAP_LOOKUP CAPRIGHT(0, 0x0000000000000400ULL)
#define CAP_FCHMOD CAPRIGHT(0, 0x0000000000002000ULL)
#define CAP_FCHMODAT (CAP_FCHMOD | CAP_LOOKUP)
There is new API to manage the new cap_rights_t structure:
cap_rights_t *cap_rights_init(cap_rights_t *rights, ...);
void cap_rights_set(cap_rights_t *rights, ...);
void cap_rights_clear(cap_rights_t *rights, ...);
bool cap_rights_is_set(const cap_rights_t *rights, ...);
bool cap_rights_is_valid(const cap_rights_t *rights);
void cap_rights_merge(cap_rights_t *dst, const cap_rights_t *src);
void cap_rights_remove(cap_rights_t *dst, const cap_rights_t *src);
bool cap_rights_contains(const cap_rights_t *big, const cap_rights_t *little);
Capability rights to the cap_rights_init(), cap_rights_set(),
cap_rights_clear() and cap_rights_is_set() functions are provided by
separating them with commas, eg:
cap_rights_t rights;
cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_FSTAT);
There is no need to terminate the list of rights, as those functions are
actually macros that take care of the termination, eg:
#define cap_rights_set(rights, ...) \
__cap_rights_set((rights), __VA_ARGS__, 0ULL)
void __cap_rights_set(cap_rights_t *rights, ...);
Thanks to using one bit as an array index we can assert in those functions that
there are no two rights belonging to different array elements provided
together. For example this is illegal and will be detected, because CAP_LOOKUP
belongs to element 0 and CAP_PDKILL to element 1:
cap_rights_init(&rights, CAP_LOOKUP | CAP_PDKILL);
Providing several rights that belongs to the same array's element this way is
correct, but is not advised. It should only be used for aliases definition.
This commit also breaks compatibility with some existing Capsicum system calls,
but I see no other way to do that. This should be fine as Capsicum is still
experimental and this change is not going to 9.x.
Sponsored by: The FreeBSD Foundation
2013-09-05 00:09:56 +00:00
|
|
|
cap_rights_t rights;
|
2011-05-04 09:05:39 +00:00
|
|
|
struct file *fp;
|
|
|
|
int error;
|
|
|
|
struct v4l2_format vformat;
|
|
|
|
struct l_v4l2_format l_vformat;
|
|
|
|
struct v4l2_standard vstd;
|
|
|
|
struct l_v4l2_standard l_vstd;
|
|
|
|
struct l_v4l2_buffer l_vbuf;
|
|
|
|
struct v4l2_buffer vbuf;
|
|
|
|
struct v4l2_input vinp;
|
|
|
|
|
|
|
|
switch (args->cmd & 0xffff) {
|
|
|
|
case LINUX_VIDIOC_RESERVED:
|
|
|
|
case LINUX_VIDIOC_LOG_STATUS:
|
|
|
|
if ((args->cmd & IOC_DIRMASK) != LINUX_IOC_VOID)
|
2018-03-12 15:35:24 +00:00
|
|
|
return (ENOIOCTL);
|
2011-05-04 09:05:39 +00:00
|
|
|
args->cmd = (args->cmd & 0xffff) | IOC_VOID;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case LINUX_VIDIOC_OVERLAY:
|
|
|
|
case LINUX_VIDIOC_STREAMON:
|
|
|
|
case LINUX_VIDIOC_STREAMOFF:
|
|
|
|
case LINUX_VIDIOC_S_STD:
|
|
|
|
case LINUX_VIDIOC_S_TUNER:
|
|
|
|
case LINUX_VIDIOC_S_AUDIO:
|
|
|
|
case LINUX_VIDIOC_S_AUDOUT:
|
|
|
|
case LINUX_VIDIOC_S_MODULATOR:
|
|
|
|
case LINUX_VIDIOC_S_FREQUENCY:
|
|
|
|
case LINUX_VIDIOC_S_CROP:
|
|
|
|
case LINUX_VIDIOC_S_JPEGCOMP:
|
|
|
|
case LINUX_VIDIOC_S_PRIORITY:
|
|
|
|
case LINUX_VIDIOC_DBG_S_REGISTER:
|
|
|
|
case LINUX_VIDIOC_S_HW_FREQ_SEEK:
|
|
|
|
case LINUX_VIDIOC_SUBSCRIBE_EVENT:
|
|
|
|
case LINUX_VIDIOC_UNSUBSCRIBE_EVENT:
|
|
|
|
args->cmd = (args->cmd & ~IOC_DIRMASK) | IOC_IN;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case LINUX_VIDIOC_QUERYCAP:
|
|
|
|
case LINUX_VIDIOC_G_STD:
|
|
|
|
case LINUX_VIDIOC_G_AUDIO:
|
|
|
|
case LINUX_VIDIOC_G_INPUT:
|
|
|
|
case LINUX_VIDIOC_G_OUTPUT:
|
|
|
|
case LINUX_VIDIOC_G_AUDOUT:
|
|
|
|
case LINUX_VIDIOC_G_JPEGCOMP:
|
|
|
|
case LINUX_VIDIOC_QUERYSTD:
|
|
|
|
case LINUX_VIDIOC_G_PRIORITY:
|
|
|
|
case LINUX_VIDIOC_QUERY_DV_PRESET:
|
|
|
|
args->cmd = (args->cmd & ~IOC_DIRMASK) | IOC_OUT;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case LINUX_VIDIOC_ENUM_FMT:
|
|
|
|
case LINUX_VIDIOC_REQBUFS:
|
|
|
|
case LINUX_VIDIOC_G_PARM:
|
|
|
|
case LINUX_VIDIOC_S_PARM:
|
|
|
|
case LINUX_VIDIOC_G_CTRL:
|
|
|
|
case LINUX_VIDIOC_S_CTRL:
|
|
|
|
case LINUX_VIDIOC_G_TUNER:
|
|
|
|
case LINUX_VIDIOC_QUERYCTRL:
|
|
|
|
case LINUX_VIDIOC_QUERYMENU:
|
|
|
|
case LINUX_VIDIOC_S_INPUT:
|
|
|
|
case LINUX_VIDIOC_S_OUTPUT:
|
|
|
|
case LINUX_VIDIOC_ENUMOUTPUT:
|
|
|
|
case LINUX_VIDIOC_G_MODULATOR:
|
|
|
|
case LINUX_VIDIOC_G_FREQUENCY:
|
|
|
|
case LINUX_VIDIOC_CROPCAP:
|
|
|
|
case LINUX_VIDIOC_G_CROP:
|
|
|
|
case LINUX_VIDIOC_ENUMAUDIO:
|
|
|
|
case LINUX_VIDIOC_ENUMAUDOUT:
|
|
|
|
case LINUX_VIDIOC_G_SLICED_VBI_CAP:
|
|
|
|
#ifdef VIDIOC_ENUM_FRAMESIZES
|
|
|
|
case LINUX_VIDIOC_ENUM_FRAMESIZES:
|
|
|
|
case LINUX_VIDIOC_ENUM_FRAMEINTERVALS:
|
|
|
|
case LINUX_VIDIOC_ENCODER_CMD:
|
|
|
|
case LINUX_VIDIOC_TRY_ENCODER_CMD:
|
|
|
|
#endif
|
|
|
|
case LINUX_VIDIOC_DBG_G_REGISTER:
|
|
|
|
case LINUX_VIDIOC_DBG_G_CHIP_IDENT:
|
|
|
|
case LINUX_VIDIOC_ENUM_DV_PRESETS:
|
|
|
|
case LINUX_VIDIOC_S_DV_PRESET:
|
|
|
|
case LINUX_VIDIOC_G_DV_PRESET:
|
|
|
|
case LINUX_VIDIOC_S_DV_TIMINGS:
|
|
|
|
case LINUX_VIDIOC_G_DV_TIMINGS:
|
|
|
|
args->cmd = (args->cmd & ~IOC_DIRMASK) | IOC_INOUT;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case LINUX_VIDIOC_G_FMT:
|
|
|
|
case LINUX_VIDIOC_S_FMT:
|
|
|
|
case LINUX_VIDIOC_TRY_FMT:
|
|
|
|
error = copyin((void *)args->arg, &l_vformat, sizeof(l_vformat));
|
|
|
|
if (error)
|
|
|
|
return (error);
|
Change the cap_rights_t type from uint64_t to a structure that we can extend
in the future in a backward compatible (API and ABI) way.
The cap_rights_t represents capability rights. We used to use one bit to
represent one right, but we are running out of spare bits. Currently the new
structure provides place for 114 rights (so 50 more than the previous
cap_rights_t), but it is possible to grow the structure to hold at least 285
rights, although we can make it even larger if 285 rights won't be enough.
The structure definition looks like this:
struct cap_rights {
uint64_t cr_rights[CAP_RIGHTS_VERSION + 2];
};
The initial CAP_RIGHTS_VERSION is 0.
The top two bits in the first element of the cr_rights[] array contain total
number of elements in the array - 2. This means if those two bits are equal to
0, we have 2 array elements.
The top two bits in all remaining array elements should be 0.
The next five bits in all array elements contain array index. Only one bit is
used and bit position in this five-bits range defines array index. This means
there can be at most five array elements in the future.
To define new right the CAPRIGHT() macro must be used. The macro takes two
arguments - an array index and a bit to set, eg.
#define CAP_PDKILL CAPRIGHT(1, 0x0000000000000800ULL)
We still support aliases that combine few rights, but the rights have to belong
to the same array element, eg:
#define CAP_LOOKUP CAPRIGHT(0, 0x0000000000000400ULL)
#define CAP_FCHMOD CAPRIGHT(0, 0x0000000000002000ULL)
#define CAP_FCHMODAT (CAP_FCHMOD | CAP_LOOKUP)
There is new API to manage the new cap_rights_t structure:
cap_rights_t *cap_rights_init(cap_rights_t *rights, ...);
void cap_rights_set(cap_rights_t *rights, ...);
void cap_rights_clear(cap_rights_t *rights, ...);
bool cap_rights_is_set(const cap_rights_t *rights, ...);
bool cap_rights_is_valid(const cap_rights_t *rights);
void cap_rights_merge(cap_rights_t *dst, const cap_rights_t *src);
void cap_rights_remove(cap_rights_t *dst, const cap_rights_t *src);
bool cap_rights_contains(const cap_rights_t *big, const cap_rights_t *little);
Capability rights to the cap_rights_init(), cap_rights_set(),
cap_rights_clear() and cap_rights_is_set() functions are provided by
separating them with commas, eg:
cap_rights_t rights;
cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_FSTAT);
There is no need to terminate the list of rights, as those functions are
actually macros that take care of the termination, eg:
#define cap_rights_set(rights, ...) \
__cap_rights_set((rights), __VA_ARGS__, 0ULL)
void __cap_rights_set(cap_rights_t *rights, ...);
Thanks to using one bit as an array index we can assert in those functions that
there are no two rights belonging to different array elements provided
together. For example this is illegal and will be detected, because CAP_LOOKUP
belongs to element 0 and CAP_PDKILL to element 1:
cap_rights_init(&rights, CAP_LOOKUP | CAP_PDKILL);
Providing several rights that belongs to the same array's element this way is
correct, but is not advised. It should only be used for aliases definition.
This commit also breaks compatibility with some existing Capsicum system calls,
but I see no other way to do that. This should be fine as Capsicum is still
experimental and this change is not going to 9.x.
Sponsored by: The FreeBSD Foundation
2013-09-05 00:09:56 +00:00
|
|
|
error = fget(td, args->fd,
|
|
|
|
cap_rights_init(&rights, CAP_IOCTL), &fp);
|
|
|
|
if (error)
|
2011-05-04 09:05:39 +00:00
|
|
|
return (error);
|
|
|
|
if (linux_to_bsd_v4l2_format(&l_vformat, &vformat) != 0)
|
|
|
|
error = EINVAL;
|
|
|
|
else if ((args->cmd & 0xffff) == LINUX_VIDIOC_G_FMT)
|
|
|
|
error = fo_ioctl(fp, VIDIOC_G_FMT, &vformat,
|
|
|
|
td->td_ucred, td);
|
|
|
|
else if ((args->cmd & 0xffff) == LINUX_VIDIOC_S_FMT)
|
|
|
|
error = fo_ioctl(fp, VIDIOC_S_FMT, &vformat,
|
|
|
|
td->td_ucred, td);
|
|
|
|
else
|
|
|
|
error = fo_ioctl(fp, VIDIOC_TRY_FMT, &vformat,
|
|
|
|
td->td_ucred, td);
|
|
|
|
bsd_to_linux_v4l2_format(&vformat, &l_vformat);
|
|
|
|
copyout(&l_vformat, (void *)args->arg, sizeof(l_vformat));
|
|
|
|
fdrop(fp, td);
|
|
|
|
return (error);
|
|
|
|
|
|
|
|
case LINUX_VIDIOC_ENUMSTD:
|
|
|
|
error = copyin((void *)args->arg, &l_vstd, sizeof(l_vstd));
|
|
|
|
if (error)
|
|
|
|
return (error);
|
|
|
|
linux_to_bsd_v4l2_standard(&l_vstd, &vstd);
|
Change the cap_rights_t type from uint64_t to a structure that we can extend
in the future in a backward compatible (API and ABI) way.
The cap_rights_t represents capability rights. We used to use one bit to
represent one right, but we are running out of spare bits. Currently the new
structure provides place for 114 rights (so 50 more than the previous
cap_rights_t), but it is possible to grow the structure to hold at least 285
rights, although we can make it even larger if 285 rights won't be enough.
The structure definition looks like this:
struct cap_rights {
uint64_t cr_rights[CAP_RIGHTS_VERSION + 2];
};
The initial CAP_RIGHTS_VERSION is 0.
The top two bits in the first element of the cr_rights[] array contain total
number of elements in the array - 2. This means if those two bits are equal to
0, we have 2 array elements.
The top two bits in all remaining array elements should be 0.
The next five bits in all array elements contain array index. Only one bit is
used and bit position in this five-bits range defines array index. This means
there can be at most five array elements in the future.
To define new right the CAPRIGHT() macro must be used. The macro takes two
arguments - an array index and a bit to set, eg.
#define CAP_PDKILL CAPRIGHT(1, 0x0000000000000800ULL)
We still support aliases that combine few rights, but the rights have to belong
to the same array element, eg:
#define CAP_LOOKUP CAPRIGHT(0, 0x0000000000000400ULL)
#define CAP_FCHMOD CAPRIGHT(0, 0x0000000000002000ULL)
#define CAP_FCHMODAT (CAP_FCHMOD | CAP_LOOKUP)
There is new API to manage the new cap_rights_t structure:
cap_rights_t *cap_rights_init(cap_rights_t *rights, ...);
void cap_rights_set(cap_rights_t *rights, ...);
void cap_rights_clear(cap_rights_t *rights, ...);
bool cap_rights_is_set(const cap_rights_t *rights, ...);
bool cap_rights_is_valid(const cap_rights_t *rights);
void cap_rights_merge(cap_rights_t *dst, const cap_rights_t *src);
void cap_rights_remove(cap_rights_t *dst, const cap_rights_t *src);
bool cap_rights_contains(const cap_rights_t *big, const cap_rights_t *little);
Capability rights to the cap_rights_init(), cap_rights_set(),
cap_rights_clear() and cap_rights_is_set() functions are provided by
separating them with commas, eg:
cap_rights_t rights;
cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_FSTAT);
There is no need to terminate the list of rights, as those functions are
actually macros that take care of the termination, eg:
#define cap_rights_set(rights, ...) \
__cap_rights_set((rights), __VA_ARGS__, 0ULL)
void __cap_rights_set(cap_rights_t *rights, ...);
Thanks to using one bit as an array index we can assert in those functions that
there are no two rights belonging to different array elements provided
together. For example this is illegal and will be detected, because CAP_LOOKUP
belongs to element 0 and CAP_PDKILL to element 1:
cap_rights_init(&rights, CAP_LOOKUP | CAP_PDKILL);
Providing several rights that belongs to the same array's element this way is
correct, but is not advised. It should only be used for aliases definition.
This commit also breaks compatibility with some existing Capsicum system calls,
but I see no other way to do that. This should be fine as Capsicum is still
experimental and this change is not going to 9.x.
Sponsored by: The FreeBSD Foundation
2013-09-05 00:09:56 +00:00
|
|
|
error = fget(td, args->fd,
|
|
|
|
cap_rights_init(&rights, CAP_IOCTL), &fp);
|
|
|
|
if (error)
|
2011-05-04 09:05:39 +00:00
|
|
|
return (error);
|
|
|
|
error = fo_ioctl(fp, VIDIOC_ENUMSTD, (caddr_t)&vstd,
|
|
|
|
td->td_ucred, td);
|
|
|
|
if (error) {
|
|
|
|
fdrop(fp, td);
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
bsd_to_linux_v4l2_standard(&vstd, &l_vstd);
|
|
|
|
error = copyout(&l_vstd, (void *)args->arg, sizeof(l_vstd));
|
|
|
|
fdrop(fp, td);
|
|
|
|
return (error);
|
|
|
|
|
|
|
|
case LINUX_VIDIOC_ENUMINPUT:
|
|
|
|
/*
|
|
|
|
* The Linux struct l_v4l2_input differs only in size,
|
|
|
|
* it has no padding at the end.
|
|
|
|
*/
|
|
|
|
error = copyin((void *)args->arg, &vinp,
|
|
|
|
sizeof(struct l_v4l2_input));
|
|
|
|
if (error != 0)
|
|
|
|
return (error);
|
Change the cap_rights_t type from uint64_t to a structure that we can extend
in the future in a backward compatible (API and ABI) way.
The cap_rights_t represents capability rights. We used to use one bit to
represent one right, but we are running out of spare bits. Currently the new
structure provides place for 114 rights (so 50 more than the previous
cap_rights_t), but it is possible to grow the structure to hold at least 285
rights, although we can make it even larger if 285 rights won't be enough.
The structure definition looks like this:
struct cap_rights {
uint64_t cr_rights[CAP_RIGHTS_VERSION + 2];
};
The initial CAP_RIGHTS_VERSION is 0.
The top two bits in the first element of the cr_rights[] array contain total
number of elements in the array - 2. This means if those two bits are equal to
0, we have 2 array elements.
The top two bits in all remaining array elements should be 0.
The next five bits in all array elements contain array index. Only one bit is
used and bit position in this five-bits range defines array index. This means
there can be at most five array elements in the future.
To define new right the CAPRIGHT() macro must be used. The macro takes two
arguments - an array index and a bit to set, eg.
#define CAP_PDKILL CAPRIGHT(1, 0x0000000000000800ULL)
We still support aliases that combine few rights, but the rights have to belong
to the same array element, eg:
#define CAP_LOOKUP CAPRIGHT(0, 0x0000000000000400ULL)
#define CAP_FCHMOD CAPRIGHT(0, 0x0000000000002000ULL)
#define CAP_FCHMODAT (CAP_FCHMOD | CAP_LOOKUP)
There is new API to manage the new cap_rights_t structure:
cap_rights_t *cap_rights_init(cap_rights_t *rights, ...);
void cap_rights_set(cap_rights_t *rights, ...);
void cap_rights_clear(cap_rights_t *rights, ...);
bool cap_rights_is_set(const cap_rights_t *rights, ...);
bool cap_rights_is_valid(const cap_rights_t *rights);
void cap_rights_merge(cap_rights_t *dst, const cap_rights_t *src);
void cap_rights_remove(cap_rights_t *dst, const cap_rights_t *src);
bool cap_rights_contains(const cap_rights_t *big, const cap_rights_t *little);
Capability rights to the cap_rights_init(), cap_rights_set(),
cap_rights_clear() and cap_rights_is_set() functions are provided by
separating them with commas, eg:
cap_rights_t rights;
cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_FSTAT);
There is no need to terminate the list of rights, as those functions are
actually macros that take care of the termination, eg:
#define cap_rights_set(rights, ...) \
__cap_rights_set((rights), __VA_ARGS__, 0ULL)
void __cap_rights_set(cap_rights_t *rights, ...);
Thanks to using one bit as an array index we can assert in those functions that
there are no two rights belonging to different array elements provided
together. For example this is illegal and will be detected, because CAP_LOOKUP
belongs to element 0 and CAP_PDKILL to element 1:
cap_rights_init(&rights, CAP_LOOKUP | CAP_PDKILL);
Providing several rights that belongs to the same array's element this way is
correct, but is not advised. It should only be used for aliases definition.
This commit also breaks compatibility with some existing Capsicum system calls,
but I see no other way to do that. This should be fine as Capsicum is still
experimental and this change is not going to 9.x.
Sponsored by: The FreeBSD Foundation
2013-09-05 00:09:56 +00:00
|
|
|
error = fget(td, args->fd,
|
|
|
|
cap_rights_init(&rights, CAP_IOCTL), &fp);
|
|
|
|
if (error != 0)
|
2011-05-04 09:05:39 +00:00
|
|
|
return (error);
|
|
|
|
error = fo_ioctl(fp, VIDIOC_ENUMINPUT, (caddr_t)&vinp,
|
|
|
|
td->td_ucred, td);
|
|
|
|
if (error) {
|
|
|
|
fdrop(fp, td);
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
error = copyout(&vinp, (void *)args->arg,
|
|
|
|
sizeof(struct l_v4l2_input));
|
|
|
|
fdrop(fp, td);
|
|
|
|
return (error);
|
|
|
|
|
|
|
|
case LINUX_VIDIOC_QUERYBUF:
|
|
|
|
case LINUX_VIDIOC_QBUF:
|
|
|
|
case LINUX_VIDIOC_DQBUF:
|
|
|
|
error = copyin((void *)args->arg, &l_vbuf, sizeof(l_vbuf));
|
|
|
|
if (error)
|
|
|
|
return (error);
|
Change the cap_rights_t type from uint64_t to a structure that we can extend
in the future in a backward compatible (API and ABI) way.
The cap_rights_t represents capability rights. We used to use one bit to
represent one right, but we are running out of spare bits. Currently the new
structure provides place for 114 rights (so 50 more than the previous
cap_rights_t), but it is possible to grow the structure to hold at least 285
rights, although we can make it even larger if 285 rights won't be enough.
The structure definition looks like this:
struct cap_rights {
uint64_t cr_rights[CAP_RIGHTS_VERSION + 2];
};
The initial CAP_RIGHTS_VERSION is 0.
The top two bits in the first element of the cr_rights[] array contain total
number of elements in the array - 2. This means if those two bits are equal to
0, we have 2 array elements.
The top two bits in all remaining array elements should be 0.
The next five bits in all array elements contain array index. Only one bit is
used and bit position in this five-bits range defines array index. This means
there can be at most five array elements in the future.
To define new right the CAPRIGHT() macro must be used. The macro takes two
arguments - an array index and a bit to set, eg.
#define CAP_PDKILL CAPRIGHT(1, 0x0000000000000800ULL)
We still support aliases that combine few rights, but the rights have to belong
to the same array element, eg:
#define CAP_LOOKUP CAPRIGHT(0, 0x0000000000000400ULL)
#define CAP_FCHMOD CAPRIGHT(0, 0x0000000000002000ULL)
#define CAP_FCHMODAT (CAP_FCHMOD | CAP_LOOKUP)
There is new API to manage the new cap_rights_t structure:
cap_rights_t *cap_rights_init(cap_rights_t *rights, ...);
void cap_rights_set(cap_rights_t *rights, ...);
void cap_rights_clear(cap_rights_t *rights, ...);
bool cap_rights_is_set(const cap_rights_t *rights, ...);
bool cap_rights_is_valid(const cap_rights_t *rights);
void cap_rights_merge(cap_rights_t *dst, const cap_rights_t *src);
void cap_rights_remove(cap_rights_t *dst, const cap_rights_t *src);
bool cap_rights_contains(const cap_rights_t *big, const cap_rights_t *little);
Capability rights to the cap_rights_init(), cap_rights_set(),
cap_rights_clear() and cap_rights_is_set() functions are provided by
separating them with commas, eg:
cap_rights_t rights;
cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_FSTAT);
There is no need to terminate the list of rights, as those functions are
actually macros that take care of the termination, eg:
#define cap_rights_set(rights, ...) \
__cap_rights_set((rights), __VA_ARGS__, 0ULL)
void __cap_rights_set(cap_rights_t *rights, ...);
Thanks to using one bit as an array index we can assert in those functions that
there are no two rights belonging to different array elements provided
together. For example this is illegal and will be detected, because CAP_LOOKUP
belongs to element 0 and CAP_PDKILL to element 1:
cap_rights_init(&rights, CAP_LOOKUP | CAP_PDKILL);
Providing several rights that belongs to the same array's element this way is
correct, but is not advised. It should only be used for aliases definition.
This commit also breaks compatibility with some existing Capsicum system calls,
but I see no other way to do that. This should be fine as Capsicum is still
experimental and this change is not going to 9.x.
Sponsored by: The FreeBSD Foundation
2013-09-05 00:09:56 +00:00
|
|
|
error = fget(td, args->fd,
|
|
|
|
cap_rights_init(&rights, CAP_IOCTL), &fp);
|
|
|
|
if (error)
|
2011-05-04 09:05:39 +00:00
|
|
|
return (error);
|
|
|
|
linux_to_bsd_v4l2_buffer(&l_vbuf, &vbuf);
|
|
|
|
if ((args->cmd & 0xffff) == LINUX_VIDIOC_QUERYBUF)
|
|
|
|
error = fo_ioctl(fp, VIDIOC_QUERYBUF, &vbuf,
|
|
|
|
td->td_ucred, td);
|
|
|
|
else if ((args->cmd & 0xffff) == LINUX_VIDIOC_QBUF)
|
|
|
|
error = fo_ioctl(fp, VIDIOC_QBUF, &vbuf,
|
|
|
|
td->td_ucred, td);
|
|
|
|
else
|
|
|
|
error = fo_ioctl(fp, VIDIOC_DQBUF, &vbuf,
|
|
|
|
td->td_ucred, td);
|
|
|
|
bsd_to_linux_v4l2_buffer(&vbuf, &l_vbuf);
|
|
|
|
copyout(&l_vbuf, (void *)args->arg, sizeof(l_vbuf));
|
|
|
|
fdrop(fp, td);
|
|
|
|
return (error);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* XXX TODO - these need 32 -> 64 bit conversion:
|
|
|
|
* (are any of them needed for webcams?)
|
|
|
|
*/
|
|
|
|
case LINUX_VIDIOC_G_FBUF:
|
|
|
|
case LINUX_VIDIOC_S_FBUF:
|
|
|
|
|
|
|
|
case LINUX_VIDIOC_G_EXT_CTRLS:
|
|
|
|
case LINUX_VIDIOC_S_EXT_CTRLS:
|
|
|
|
case LINUX_VIDIOC_TRY_EXT_CTRLS:
|
|
|
|
|
|
|
|
case LINUX_VIDIOC_DQEVENT:
|
|
|
|
|
|
|
|
default: return (ENOIOCTL);
|
|
|
|
}
|
|
|
|
|
2011-09-16 13:58:51 +00:00
|
|
|
error = sys_ioctl(td, (struct ioctl_args *)args);
|
2011-05-04 09:05:39 +00:00
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
2010-01-18 22:46:06 +00:00
|
|
|
/*
|
2010-05-24 07:04:00 +00:00
|
|
|
* Support for emulators/linux-libusb. This port uses FBSD_LUSB* macros
|
|
|
|
* instead of USB* ones. This lets us to provide correct values for cmd.
|
|
|
|
* 0xffffffe0 -- 0xffffffff range seemed to be the least collision-prone.
|
2010-01-18 22:46:06 +00:00
|
|
|
*/
|
|
|
|
static int
|
|
|
|
linux_ioctl_fbsd_usb(struct thread *td, struct linux_ioctl_args *args)
|
|
|
|
{
|
2010-05-24 07:04:00 +00:00
|
|
|
int error;
|
2010-01-18 22:46:06 +00:00
|
|
|
|
2010-05-24 07:04:00 +00:00
|
|
|
error = 0;
|
|
|
|
switch (args->cmd) {
|
|
|
|
case FBSD_LUSB_DEVICEENUMERATE:
|
|
|
|
args->cmd = USB_DEVICEENUMERATE;
|
|
|
|
break;
|
|
|
|
case FBSD_LUSB_DEV_QUIRK_ADD:
|
|
|
|
args->cmd = USB_DEV_QUIRK_ADD;
|
|
|
|
break;
|
|
|
|
case FBSD_LUSB_DEV_QUIRK_GET:
|
|
|
|
args->cmd = USB_DEV_QUIRK_GET;
|
|
|
|
break;
|
|
|
|
case FBSD_LUSB_DEV_QUIRK_REMOVE:
|
|
|
|
args->cmd = USB_DEV_QUIRK_REMOVE;
|
|
|
|
break;
|
|
|
|
case FBSD_LUSB_DO_REQUEST:
|
|
|
|
args->cmd = USB_DO_REQUEST;
|
|
|
|
break;
|
|
|
|
case FBSD_LUSB_FS_CLEAR_STALL_SYNC:
|
|
|
|
args->cmd = USB_FS_CLEAR_STALL_SYNC;
|
|
|
|
break;
|
|
|
|
case FBSD_LUSB_FS_CLOSE:
|
|
|
|
args->cmd = USB_FS_CLOSE;
|
|
|
|
break;
|
|
|
|
case FBSD_LUSB_FS_COMPLETE:
|
|
|
|
args->cmd = USB_FS_COMPLETE;
|
|
|
|
break;
|
|
|
|
case FBSD_LUSB_FS_INIT:
|
|
|
|
args->cmd = USB_FS_INIT;
|
|
|
|
break;
|
|
|
|
case FBSD_LUSB_FS_OPEN:
|
|
|
|
args->cmd = USB_FS_OPEN;
|
|
|
|
break;
|
|
|
|
case FBSD_LUSB_FS_START:
|
|
|
|
args->cmd = USB_FS_START;
|
|
|
|
break;
|
|
|
|
case FBSD_LUSB_FS_STOP:
|
|
|
|
args->cmd = USB_FS_STOP;
|
|
|
|
break;
|
|
|
|
case FBSD_LUSB_FS_UNINIT:
|
|
|
|
args->cmd = USB_FS_UNINIT;
|
|
|
|
break;
|
|
|
|
case FBSD_LUSB_GET_CONFIG:
|
|
|
|
args->cmd = USB_GET_CONFIG;
|
|
|
|
break;
|
|
|
|
case FBSD_LUSB_GET_DEVICEINFO:
|
|
|
|
args->cmd = USB_GET_DEVICEINFO;
|
|
|
|
break;
|
|
|
|
case FBSD_LUSB_GET_DEVICE_DESC:
|
|
|
|
args->cmd = USB_GET_DEVICE_DESC;
|
|
|
|
break;
|
|
|
|
case FBSD_LUSB_GET_FULL_DESC:
|
|
|
|
args->cmd = USB_GET_FULL_DESC;
|
|
|
|
break;
|
|
|
|
case FBSD_LUSB_GET_IFACE_DRIVER:
|
|
|
|
args->cmd = USB_GET_IFACE_DRIVER;
|
|
|
|
break;
|
|
|
|
case FBSD_LUSB_GET_PLUGTIME:
|
|
|
|
args->cmd = USB_GET_PLUGTIME;
|
|
|
|
break;
|
|
|
|
case FBSD_LUSB_GET_POWER_MODE:
|
|
|
|
args->cmd = USB_GET_POWER_MODE;
|
|
|
|
break;
|
|
|
|
case FBSD_LUSB_GET_REPORT_DESC:
|
|
|
|
args->cmd = USB_GET_REPORT_DESC;
|
|
|
|
break;
|
|
|
|
case FBSD_LUSB_GET_REPORT_ID:
|
|
|
|
args->cmd = USB_GET_REPORT_ID;
|
|
|
|
break;
|
|
|
|
case FBSD_LUSB_GET_TEMPLATE:
|
|
|
|
args->cmd = USB_GET_TEMPLATE;
|
|
|
|
break;
|
|
|
|
case FBSD_LUSB_IFACE_DRIVER_ACTIVE:
|
|
|
|
args->cmd = USB_IFACE_DRIVER_ACTIVE;
|
|
|
|
break;
|
|
|
|
case FBSD_LUSB_IFACE_DRIVER_DETACH:
|
|
|
|
args->cmd = USB_IFACE_DRIVER_DETACH;
|
|
|
|
break;
|
|
|
|
case FBSD_LUSB_QUIRK_NAME_GET:
|
|
|
|
args->cmd = USB_QUIRK_NAME_GET;
|
|
|
|
break;
|
|
|
|
case FBSD_LUSB_READ_DIR:
|
|
|
|
args->cmd = USB_READ_DIR;
|
|
|
|
break;
|
|
|
|
case FBSD_LUSB_SET_ALTINTERFACE:
|
|
|
|
args->cmd = USB_SET_ALTINTERFACE;
|
|
|
|
break;
|
|
|
|
case FBSD_LUSB_SET_CONFIG:
|
|
|
|
args->cmd = USB_SET_CONFIG;
|
|
|
|
break;
|
|
|
|
case FBSD_LUSB_SET_IMMED:
|
|
|
|
args->cmd = USB_SET_IMMED;
|
|
|
|
break;
|
|
|
|
case FBSD_LUSB_SET_POWER_MODE:
|
|
|
|
args->cmd = USB_SET_POWER_MODE;
|
|
|
|
break;
|
|
|
|
case FBSD_LUSB_SET_TEMPLATE:
|
|
|
|
args->cmd = USB_SET_TEMPLATE;
|
|
|
|
break;
|
2013-07-14 10:13:01 +00:00
|
|
|
case FBSD_LUSB_FS_OPEN_STREAM:
|
|
|
|
args->cmd = USB_FS_OPEN_STREAM;
|
|
|
|
break;
|
|
|
|
case FBSD_LUSB_GET_DEV_PORT_PATH:
|
|
|
|
args->cmd = USB_GET_DEV_PORT_PATH;
|
|
|
|
break;
|
|
|
|
case FBSD_LUSB_GET_POWER_USAGE:
|
|
|
|
args->cmd = USB_GET_POWER_USAGE;
|
|
|
|
break;
|
2010-05-24 07:04:00 +00:00
|
|
|
default:
|
|
|
|
error = ENOIOCTL;
|
|
|
|
}
|
|
|
|
if (error != ENOIOCTL)
|
2011-09-16 13:58:51 +00:00
|
|
|
error = sys_ioctl(td, (struct ioctl_args *)args);
|
2010-05-24 07:04:00 +00:00
|
|
|
return (error);
|
2010-01-18 22:46:06 +00:00
|
|
|
}
|
|
|
|
|
2017-04-23 07:43:50 +00:00
|
|
|
/*
|
|
|
|
* Some evdev ioctls must be translated.
|
|
|
|
* - EVIOCGMTSLOTS is a IOC_READ ioctl on Linux although it has input data
|
|
|
|
* (must be IOC_INOUT on FreeBSD).
|
|
|
|
* - On Linux, EVIOCGRAB, EVIOCREVOKE and EVIOCRMFF are defined as _IOW with
|
|
|
|
* an int argument. You don't pass an int pointer to the ioctl(), however,
|
|
|
|
* but just the int directly. On FreeBSD, they are defined as _IOWINT for
|
|
|
|
* this to work.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
linux_ioctl_evdev(struct thread *td, struct linux_ioctl_args *args)
|
|
|
|
{
|
|
|
|
cap_rights_t rights;
|
|
|
|
struct file *fp;
|
|
|
|
clockid_t clock;
|
|
|
|
int error;
|
|
|
|
|
|
|
|
args->cmd = SETDIR(args->cmd);
|
|
|
|
|
|
|
|
switch (args->cmd) {
|
|
|
|
case (EVIOCGRAB & ~IOC_DIRMASK) | IOC_IN:
|
|
|
|
args->cmd = EVIOCGRAB;
|
|
|
|
break;
|
|
|
|
case (EVIOCREVOKE & ~IOC_DIRMASK) | IOC_IN:
|
|
|
|
args->cmd = EVIOCREVOKE;
|
|
|
|
break;
|
|
|
|
case (EVIOCRMFF & ~IOC_DIRMASK) | IOC_IN:
|
|
|
|
args->cmd = EVIOCRMFF;
|
|
|
|
break;
|
|
|
|
case EVIOCSCLOCKID: {
|
|
|
|
error = copyin(PTRIN(args->arg), &clock, sizeof(clock));
|
|
|
|
if (error != 0)
|
|
|
|
return (error);
|
|
|
|
if (clock & ~(LINUX_IOCTL_EVDEV_CLK))
|
|
|
|
return (EINVAL);
|
|
|
|
error = linux_to_native_clockid(&clock, clock);
|
|
|
|
if (error != 0)
|
|
|
|
return (error);
|
|
|
|
|
|
|
|
error = fget(td, args->fd,
|
|
|
|
cap_rights_init(&rights, CAP_IOCTL), &fp);
|
|
|
|
if (error != 0)
|
|
|
|
return (error);
|
|
|
|
|
|
|
|
error = fo_ioctl(fp, EVIOCSCLOCKID, &clock, td->td_ucred, td);
|
|
|
|
fdrop(fp, td);
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (IOCBASECMD(args->cmd) ==
|
|
|
|
((EVIOCGMTSLOTS(0) & ~IOC_DIRMASK) | IOC_OUT))
|
|
|
|
args->cmd = (args->cmd & ~IOC_DIRMASK) | IOC_INOUT;
|
|
|
|
|
|
|
|
return (sys_ioctl(td, (struct ioctl_args *)args));
|
|
|
|
}
|
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
/*
|
|
|
|
* main ioctl syscall function
|
|
|
|
*/
|
1999-04-29 04:37:57 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
int
|
2001-09-12 08:38:13 +00:00
|
|
|
linux_ioctl(struct thread *td, struct linux_ioctl_args *args)
|
1999-12-04 11:10:22 +00:00
|
|
|
{
|
Change the cap_rights_t type from uint64_t to a structure that we can extend
in the future in a backward compatible (API and ABI) way.
The cap_rights_t represents capability rights. We used to use one bit to
represent one right, but we are running out of spare bits. Currently the new
structure provides place for 114 rights (so 50 more than the previous
cap_rights_t), but it is possible to grow the structure to hold at least 285
rights, although we can make it even larger if 285 rights won't be enough.
The structure definition looks like this:
struct cap_rights {
uint64_t cr_rights[CAP_RIGHTS_VERSION + 2];
};
The initial CAP_RIGHTS_VERSION is 0.
The top two bits in the first element of the cr_rights[] array contain total
number of elements in the array - 2. This means if those two bits are equal to
0, we have 2 array elements.
The top two bits in all remaining array elements should be 0.
The next five bits in all array elements contain array index. Only one bit is
used and bit position in this five-bits range defines array index. This means
there can be at most five array elements in the future.
To define new right the CAPRIGHT() macro must be used. The macro takes two
arguments - an array index and a bit to set, eg.
#define CAP_PDKILL CAPRIGHT(1, 0x0000000000000800ULL)
We still support aliases that combine few rights, but the rights have to belong
to the same array element, eg:
#define CAP_LOOKUP CAPRIGHT(0, 0x0000000000000400ULL)
#define CAP_FCHMOD CAPRIGHT(0, 0x0000000000002000ULL)
#define CAP_FCHMODAT (CAP_FCHMOD | CAP_LOOKUP)
There is new API to manage the new cap_rights_t structure:
cap_rights_t *cap_rights_init(cap_rights_t *rights, ...);
void cap_rights_set(cap_rights_t *rights, ...);
void cap_rights_clear(cap_rights_t *rights, ...);
bool cap_rights_is_set(const cap_rights_t *rights, ...);
bool cap_rights_is_valid(const cap_rights_t *rights);
void cap_rights_merge(cap_rights_t *dst, const cap_rights_t *src);
void cap_rights_remove(cap_rights_t *dst, const cap_rights_t *src);
bool cap_rights_contains(const cap_rights_t *big, const cap_rights_t *little);
Capability rights to the cap_rights_init(), cap_rights_set(),
cap_rights_clear() and cap_rights_is_set() functions are provided by
separating them with commas, eg:
cap_rights_t rights;
cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_FSTAT);
There is no need to terminate the list of rights, as those functions are
actually macros that take care of the termination, eg:
#define cap_rights_set(rights, ...) \
__cap_rights_set((rights), __VA_ARGS__, 0ULL)
void __cap_rights_set(cap_rights_t *rights, ...);
Thanks to using one bit as an array index we can assert in those functions that
there are no two rights belonging to different array elements provided
together. For example this is illegal and will be detected, because CAP_LOOKUP
belongs to element 0 and CAP_PDKILL to element 1:
cap_rights_init(&rights, CAP_LOOKUP | CAP_PDKILL);
Providing several rights that belongs to the same array's element this way is
correct, but is not advised. It should only be used for aliases definition.
This commit also breaks compatibility with some existing Capsicum system calls,
but I see no other way to do that. This should be fine as Capsicum is still
experimental and this change is not going to 9.x.
Sponsored by: The FreeBSD Foundation
2013-09-05 00:09:56 +00:00
|
|
|
cap_rights_t rights;
|
1999-12-04 11:10:22 +00:00
|
|
|
struct file *fp;
|
|
|
|
struct handler_element *he;
|
|
|
|
int error, cmd;
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
2001-02-16 16:40:43 +00:00
|
|
|
if (ldebug(ioctl))
|
2001-11-17 01:20:02 +00:00
|
|
|
printf(ARGS(ioctl, "%d, %04lx, *"), args->fd,
|
|
|
|
(unsigned long)args->cmd);
|
1999-12-04 11:10:22 +00:00
|
|
|
#endif
|
|
|
|
|
Change the cap_rights_t type from uint64_t to a structure that we can extend
in the future in a backward compatible (API and ABI) way.
The cap_rights_t represents capability rights. We used to use one bit to
represent one right, but we are running out of spare bits. Currently the new
structure provides place for 114 rights (so 50 more than the previous
cap_rights_t), but it is possible to grow the structure to hold at least 285
rights, although we can make it even larger if 285 rights won't be enough.
The structure definition looks like this:
struct cap_rights {
uint64_t cr_rights[CAP_RIGHTS_VERSION + 2];
};
The initial CAP_RIGHTS_VERSION is 0.
The top two bits in the first element of the cr_rights[] array contain total
number of elements in the array - 2. This means if those two bits are equal to
0, we have 2 array elements.
The top two bits in all remaining array elements should be 0.
The next five bits in all array elements contain array index. Only one bit is
used and bit position in this five-bits range defines array index. This means
there can be at most five array elements in the future.
To define new right the CAPRIGHT() macro must be used. The macro takes two
arguments - an array index and a bit to set, eg.
#define CAP_PDKILL CAPRIGHT(1, 0x0000000000000800ULL)
We still support aliases that combine few rights, but the rights have to belong
to the same array element, eg:
#define CAP_LOOKUP CAPRIGHT(0, 0x0000000000000400ULL)
#define CAP_FCHMOD CAPRIGHT(0, 0x0000000000002000ULL)
#define CAP_FCHMODAT (CAP_FCHMOD | CAP_LOOKUP)
There is new API to manage the new cap_rights_t structure:
cap_rights_t *cap_rights_init(cap_rights_t *rights, ...);
void cap_rights_set(cap_rights_t *rights, ...);
void cap_rights_clear(cap_rights_t *rights, ...);
bool cap_rights_is_set(const cap_rights_t *rights, ...);
bool cap_rights_is_valid(const cap_rights_t *rights);
void cap_rights_merge(cap_rights_t *dst, const cap_rights_t *src);
void cap_rights_remove(cap_rights_t *dst, const cap_rights_t *src);
bool cap_rights_contains(const cap_rights_t *big, const cap_rights_t *little);
Capability rights to the cap_rights_init(), cap_rights_set(),
cap_rights_clear() and cap_rights_is_set() functions are provided by
separating them with commas, eg:
cap_rights_t rights;
cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_FSTAT);
There is no need to terminate the list of rights, as those functions are
actually macros that take care of the termination, eg:
#define cap_rights_set(rights, ...) \
__cap_rights_set((rights), __VA_ARGS__, 0ULL)
void __cap_rights_set(cap_rights_t *rights, ...);
Thanks to using one bit as an array index we can assert in those functions that
there are no two rights belonging to different array elements provided
together. For example this is illegal and will be detected, because CAP_LOOKUP
belongs to element 0 and CAP_PDKILL to element 1:
cap_rights_init(&rights, CAP_LOOKUP | CAP_PDKILL);
Providing several rights that belongs to the same array's element this way is
correct, but is not advised. It should only be used for aliases definition.
This commit also breaks compatibility with some existing Capsicum system calls,
but I see no other way to do that. This should be fine as Capsicum is still
experimental and this change is not going to 9.x.
Sponsored by: The FreeBSD Foundation
2013-09-05 00:09:56 +00:00
|
|
|
error = fget(td, args->fd, cap_rights_init(&rights, CAP_IOCTL), &fp);
|
|
|
|
if (error != 0)
|
2002-01-14 00:13:45 +00:00
|
|
|
return (error);
|
2002-01-13 11:58:06 +00:00
|
|
|
if ((fp->f_flag & (FREAD|FWRITE)) == 0) {
|
|
|
|
fdrop(fp, td);
|
1999-12-04 11:10:22 +00:00
|
|
|
return (EBADF);
|
2002-01-13 11:58:06 +00:00
|
|
|
}
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
/* Iterate over the ioctl handlers */
|
|
|
|
cmd = args->cmd & 0xffff;
|
2006-07-06 21:42:36 +00:00
|
|
|
sx_slock(&linux_ioctl_sx);
|
|
|
|
mtx_lock(&Giant);
|
1999-12-04 11:10:22 +00:00
|
|
|
TAILQ_FOREACH(he, &handlers, list) {
|
|
|
|
if (cmd >= he->low && cmd <= he->high) {
|
2001-09-12 08:38:13 +00:00
|
|
|
error = (*he->func)(td, args);
|
2002-02-20 17:06:37 +00:00
|
|
|
if (error != ENOIOCTL) {
|
2006-07-06 21:42:36 +00:00
|
|
|
mtx_unlock(&Giant);
|
|
|
|
sx_sunlock(&linux_ioctl_sx);
|
2002-01-13 11:58:06 +00:00
|
|
|
fdrop(fp, td);
|
1999-12-04 11:10:22 +00:00
|
|
|
return (error);
|
2002-02-20 17:06:37 +00:00
|
|
|
}
|
1999-12-04 11:10:22 +00:00
|
|
|
}
|
|
|
|
}
|
2006-07-06 21:42:36 +00:00
|
|
|
mtx_unlock(&Giant);
|
|
|
|
sx_sunlock(&linux_ioctl_sx);
|
2002-01-13 11:58:06 +00:00
|
|
|
fdrop(fp, td);
|
1999-12-04 11:10:22 +00:00
|
|
|
|
2015-05-24 18:12:04 +00:00
|
|
|
switch (args->cmd & 0xffff) {
|
|
|
|
case LINUX_BTRFS_IOC_CLONE:
|
|
|
|
return (ENOTSUP);
|
|
|
|
|
|
|
|
default:
|
|
|
|
linux_msg(td, "ioctl fd=%d, cmd=0x%x ('%c',%d) is not implemented",
|
|
|
|
args->fd, (int)(args->cmd & 0xffff),
|
|
|
|
(int)(args->cmd & 0xff00) >> 8, (int)(args->cmd & 0xff));
|
|
|
|
break;
|
|
|
|
}
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
return (EINVAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
linux_ioctl_register_handler(struct linux_ioctl_handler *h)
|
|
|
|
{
|
|
|
|
struct handler_element *he, *cur;
|
|
|
|
|
|
|
|
if (h == NULL || h->func == NULL)
|
|
|
|
return (EINVAL);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Reuse the element if the handler is already on the list, otherwise
|
|
|
|
* create a new element.
|
|
|
|
*/
|
2006-07-06 21:42:36 +00:00
|
|
|
sx_xlock(&linux_ioctl_sx);
|
1999-12-04 11:10:22 +00:00
|
|
|
TAILQ_FOREACH(he, &handlers, list) {
|
|
|
|
if (he->func == h->func)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (he == NULL) {
|
2008-10-23 15:53:51 +00:00
|
|
|
he = malloc(sizeof(*he),
|
2003-02-19 05:47:46 +00:00
|
|
|
M_LINUX, M_WAITOK);
|
1999-12-04 11:10:22 +00:00
|
|
|
he->func = h->func;
|
|
|
|
} else
|
|
|
|
TAILQ_REMOVE(&handlers, he, list);
|
2003-03-02 15:56:49 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
/* Initialize range information. */
|
|
|
|
he->low = h->low;
|
|
|
|
he->high = h->high;
|
|
|
|
he->span = h->high - h->low + 1;
|
|
|
|
|
|
|
|
/* Add the element to the list, sorted on span. */
|
|
|
|
TAILQ_FOREACH(cur, &handlers, list) {
|
|
|
|
if (cur->span > he->span) {
|
|
|
|
TAILQ_INSERT_BEFORE(cur, he, list);
|
2006-07-06 21:42:36 +00:00
|
|
|
sx_xunlock(&linux_ioctl_sx);
|
1999-12-04 11:10:22 +00:00
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
TAILQ_INSERT_TAIL(&handlers, he, list);
|
2006-07-06 21:42:36 +00:00
|
|
|
sx_xunlock(&linux_ioctl_sx);
|
1999-04-29 04:37:57 +00:00
|
|
|
|
1999-12-04 11:10:22 +00:00
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
linux_ioctl_unregister_handler(struct linux_ioctl_handler *h)
|
|
|
|
{
|
|
|
|
struct handler_element *he;
|
|
|
|
|
|
|
|
if (h == NULL || h->func == NULL)
|
|
|
|
return (EINVAL);
|
|
|
|
|
2006-07-06 21:42:36 +00:00
|
|
|
sx_xlock(&linux_ioctl_sx);
|
1999-12-04 11:10:22 +00:00
|
|
|
TAILQ_FOREACH(he, &handlers, list) {
|
|
|
|
if (he->func == h->func) {
|
|
|
|
TAILQ_REMOVE(&handlers, he, list);
|
2006-07-06 21:42:36 +00:00
|
|
|
sx_xunlock(&linux_ioctl_sx);
|
2008-10-23 15:53:51 +00:00
|
|
|
free(he, M_LINUX);
|
1999-12-04 11:10:22 +00:00
|
|
|
return (0);
|
|
|
|
}
|
1999-04-29 04:37:57 +00:00
|
|
|
}
|
2006-07-06 21:42:36 +00:00
|
|
|
sx_xunlock(&linux_ioctl_sx);
|
1999-12-04 11:10:22 +00:00
|
|
|
|
|
|
|
return (EINVAL);
|
|
|
|
}
|