• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 //! Macros and wrapper functions for dealing with ioctls.
6 
7 use std::os::raw::*;
8 use std::os::unix::io::AsRawFd;
9 
10 use libc;
11 
12 /// Raw macro to declare the expression that calculates an ioctl number
13 #[macro_export]
14 macro_rules! ioctl_expr {
15     ($dir:expr, $ty:expr, $nr:expr, $size:expr) => {
16         (($dir << $crate::ioctl::_IOC_DIRSHIFT)
17             | ($ty << $crate::ioctl::_IOC_TYPESHIFT)
18             | ($nr << $crate::ioctl::_IOC_NRSHIFT)
19             | ($size << $crate::ioctl::_IOC_SIZESHIFT)) as ::std::os::raw::c_ulong
20     };
21 }
22 
23 /// Raw macro to declare a function that returns an ioctl number.
24 #[macro_export]
25 macro_rules! ioctl_ioc_nr {
26     ($name:ident, $dir:expr, $ty:expr, $nr:expr, $size:expr) => {
27         #[allow(non_snake_case)]
28         pub fn $name() -> ::std::os::raw::c_ulong {
29             $crate::ioctl_expr!($dir, $ty, $nr, $size)
30         }
31     };
32     ($name:ident, $dir:expr, $ty:expr, $nr:expr, $size:expr, $($v:ident),+) => {
33         #[allow(non_snake_case)]
34         pub fn $name($($v: ::std::os::raw::c_uint),+) -> ::std::os::raw::c_ulong {
35             $crate::ioctl_expr!($dir, $ty, $nr, $size)
36         }
37     };
38 }
39 
40 /// Declare an ioctl that transfers no data.
41 #[macro_export]
42 macro_rules! ioctl_io_nr {
43     ($name:ident, $ty:expr, $nr:expr) => {
44         $crate::ioctl_ioc_nr!($name, $crate::ioctl::_IOC_NONE, $ty, $nr, 0);
45     };
46     ($name:ident, $ty:expr, $nr:expr, $($v:ident),+) => {
47         $crate::ioctl_ioc_nr!($name, $crate::ioctl::_IOC_NONE, $ty, $nr, 0, $($v),+);
48     };
49 }
50 
51 /// Declare an ioctl that reads data.
52 #[macro_export]
53 macro_rules! ioctl_ior_nr {
54     ($name:ident, $ty:expr, $nr:expr, $size:ty) => {
55         $crate::ioctl_ioc_nr!(
56             $name,
57             $crate::ioctl::_IOC_READ,
58             $ty,
59             $nr,
60             ::std::mem::size_of::<$size>() as u32
61         );
62     };
63     ($name:ident, $ty:expr, $nr:expr, $size:ty, $($v:ident),+) => {
64         $crate::ioctl_ioc_nr!(
65             $name,
66             $crate::ioctl::_IOC_READ,
67             $ty,
68             $nr,
69             ::std::mem::size_of::<$size>() as u32,
70             $($v),+
71         );
72     };
73 }
74 
75 /// Declare an ioctl that writes data.
76 #[macro_export]
77 macro_rules! ioctl_iow_nr {
78     ($name:ident, $ty:expr, $nr:expr, $size:ty) => {
79         $crate::ioctl_ioc_nr!(
80             $name,
81             $crate::ioctl::_IOC_WRITE,
82             $ty,
83             $nr,
84             ::std::mem::size_of::<$size>() as u32
85         );
86     };
87     ($name:ident, $ty:expr, $nr:expr, $size:ty, $($v:ident),+) => {
88         $crate::ioctl_ioc_nr!(
89             $name,
90             $crate::ioctl::_IOC_WRITE,
91             $ty,
92             $nr,
93             ::std::mem::size_of::<$size>() as u32,
94             $($v),+
95         );
96     };
97 }
98 
99 /// Declare an ioctl that reads and writes data.
100 #[macro_export]
101 macro_rules! ioctl_iowr_nr {
102     ($name:ident, $ty:expr, $nr:expr, $size:ty) => {
103         $crate::ioctl_ioc_nr!(
104             $name,
105             $crate::ioctl::_IOC_READ | $crate::ioctl::_IOC_WRITE,
106             $ty,
107             $nr,
108             ::std::mem::size_of::<$size>() as u32
109         );
110     };
111     ($name:ident, $ty:expr, $nr:expr, $size:ty, $($v:ident),+) => {
112         $crate::ioctl_ioc_nr!(
113             $name,
114             $crate::ioctl::_IOC_READ | $crate::ioctl::_IOC_WRITE,
115             $ty,
116             $nr,
117             ::std::mem::size_of::<$size>() as u32,
118             $($v),+
119         );
120     };
121 }
122 
123 pub const _IOC_NRBITS: c_uint = 8;
124 pub const _IOC_TYPEBITS: c_uint = 8;
125 pub const _IOC_SIZEBITS: c_uint = 14;
126 pub const _IOC_DIRBITS: c_uint = 2;
127 pub const _IOC_NRMASK: c_uint = 255;
128 pub const _IOC_TYPEMASK: c_uint = 255;
129 pub const _IOC_SIZEMASK: c_uint = 16383;
130 pub const _IOC_DIRMASK: c_uint = 3;
131 pub const _IOC_NRSHIFT: c_uint = 0;
132 pub const _IOC_TYPESHIFT: c_uint = 8;
133 pub const _IOC_SIZESHIFT: c_uint = 16;
134 pub const _IOC_DIRSHIFT: c_uint = 30;
135 pub const _IOC_NONE: c_uint = 0;
136 pub const _IOC_WRITE: c_uint = 1;
137 pub const _IOC_READ: c_uint = 2;
138 pub const IOC_IN: c_uint = 1_073_741_824;
139 pub const IOC_OUT: c_uint = 2_147_483_648;
140 pub const IOC_INOUT: c_uint = 3_221_225_472;
141 pub const IOCSIZE_MASK: c_uint = 1_073_676_288;
142 pub const IOCSIZE_SHIFT: c_uint = 16;
143 
144 /// Run an ioctl with no arguments.
ioctl<F: AsRawFd>(fd: &F, nr: c_ulong) -> c_int145 pub unsafe fn ioctl<F: AsRawFd>(fd: &F, nr: c_ulong) -> c_int {
146     libc::ioctl(fd.as_raw_fd(), nr, 0)
147 }
148 
149 /// Run an ioctl with a single value argument.
ioctl_with_val<F: AsRawFd>(fd: &F, nr: c_ulong, arg: c_ulong) -> c_int150 pub unsafe fn ioctl_with_val<F: AsRawFd>(fd: &F, nr: c_ulong, arg: c_ulong) -> c_int {
151     libc::ioctl(fd.as_raw_fd(), nr, arg)
152 }
153 
154 /// Run an ioctl with an immutable reference.
ioctl_with_ref<F: AsRawFd, T>(fd: &F, nr: c_ulong, arg: &T) -> c_int155 pub unsafe fn ioctl_with_ref<F: AsRawFd, T>(fd: &F, nr: c_ulong, arg: &T) -> c_int {
156     libc::ioctl(fd.as_raw_fd(), nr, arg as *const T as *const c_void)
157 }
158 
159 /// Run an ioctl with a mutable reference.
ioctl_with_mut_ref<F: AsRawFd, T>(fd: &F, nr: c_ulong, arg: &mut T) -> c_int160 pub unsafe fn ioctl_with_mut_ref<F: AsRawFd, T>(fd: &F, nr: c_ulong, arg: &mut T) -> c_int {
161     libc::ioctl(fd.as_raw_fd(), nr, arg as *mut T as *mut c_void)
162 }
163 
164 /// Run an ioctl with a raw pointer.
ioctl_with_ptr<F: AsRawFd, T>(fd: &F, nr: c_ulong, arg: *const T) -> c_int165 pub unsafe fn ioctl_with_ptr<F: AsRawFd, T>(fd: &F, nr: c_ulong, arg: *const T) -> c_int {
166     libc::ioctl(fd.as_raw_fd(), nr, arg as *const c_void)
167 }
168 
169 /// Run an ioctl with a mutable raw pointer.
ioctl_with_mut_ptr<F: AsRawFd, T>(fd: &F, nr: c_ulong, arg: *mut T) -> c_int170 pub unsafe fn ioctl_with_mut_ptr<F: AsRawFd, T>(fd: &F, nr: c_ulong, arg: *mut T) -> c_int {
171     libc::ioctl(fd.as_raw_fd(), nr, arg as *mut c_void)
172 }
173 
174 #[cfg(test)]
175 mod tests {
176     const TUNTAP: ::std::os::raw::c_uint = 0x54;
177     const VHOST: ::std::os::raw::c_uint = 0xaf;
178     const EVDEV: ::std::os::raw::c_uint = 0x45;
179 
180     ioctl_io_nr!(VHOST_SET_OWNER, VHOST, 0x01);
181     ioctl_ior_nr!(TUNGETFEATURES, TUNTAP, 0xcf, ::std::os::raw::c_uint);
182     ioctl_iow_nr!(TUNSETQUEUE, TUNTAP, 0xd9, ::std::os::raw::c_int);
183     ioctl_iowr_nr!(VHOST_GET_VRING_BASE, VHOST, 0x12, ::std::os::raw::c_int);
184 
185     ioctl_ior_nr!(EVIOCGBIT, EVDEV, 0x20 + evt, [u8; 128], evt);
186     ioctl_io_nr!(FAKE_IOCTL_2_ARG, EVDEV, 0x01 + x + y, x, y);
187 
188     #[test]
ioctl_macros()189     fn ioctl_macros() {
190         assert_eq!(0x0000af01, VHOST_SET_OWNER());
191         assert_eq!(0x800454cf, TUNGETFEATURES());
192         assert_eq!(0x400454d9, TUNSETQUEUE());
193         assert_eq!(0xc004af12, VHOST_GET_VRING_BASE());
194 
195         assert_eq!(0x80804522, EVIOCGBIT(2));
196         assert_eq!(0x00004509, FAKE_IOCTL_2_ARG(3, 5));
197     }
198 }
199