• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 The ChromiumOS Authors
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 // Allow missing safety comments because this file provides just thin helper functions for
8 // `libc::ioctl`. Their safety follows `libc::ioctl`'s safety.
9 #![allow(clippy::missing_safety_doc)]
10 
11 use std::os::raw::c_int;
12 use std::os::raw::c_uint;
13 use std::os::raw::c_ulong;
14 use std::os::raw::c_void;
15 
16 use crate::descriptor::AsRawDescriptor;
17 
18 /// Raw macro to declare the expression that calculates an ioctl number
19 #[macro_export]
20 macro_rules! ioctl_expr {
21     ($dir:expr, $ty:expr, $nr:expr, $size:expr) => {
22         ((($dir as $crate::linux::IoctlNr) << $crate::linux::ioctl::_IOC_DIRSHIFT)
23             | (($ty as $crate::linux::IoctlNr) << $crate::linux::ioctl::_IOC_TYPESHIFT)
24             | (($nr as $crate::linux::IoctlNr) << $crate::linux::ioctl::_IOC_NRSHIFT)
25             | (($size as $crate::linux::IoctlNr) << $crate::linux::ioctl::_IOC_SIZESHIFT))
26     };
27 }
28 
29 /// Raw macro to declare a function that returns an ioctl number.
30 #[macro_export]
31 macro_rules! ioctl_ioc_nr {
32     ($name:ident, $dir:expr, $ty:expr, $nr:expr, $size:expr) => {
33         #[allow(non_snake_case)]
34         /// Generates ioctl request number.
35         pub const fn $name() -> $crate::linux::IoctlNr {
36             $crate::ioctl_expr!($dir, $ty, $nr, $size)
37         }
38     };
39     ($name:ident, $dir:expr, $ty:expr, $nr:expr, $size:expr, $($v:ident),+) => {
40         #[allow(non_snake_case)]
41         /// Generates ioctl request number.
42         pub const fn $name($($v: ::std::os::raw::c_uint),+) -> $crate::linux::IoctlNr {
43             $crate::ioctl_expr!($dir, $ty, $nr, $size)
44         }
45     };
46 }
47 
48 /// Declare an ioctl that transfers no data.
49 #[macro_export]
50 macro_rules! ioctl_io_nr {
51     ($name:ident, $ty:expr, $nr:expr) => {
52         $crate::ioctl_ioc_nr!($name, $crate::linux::ioctl::_IOC_NONE, $ty, $nr, 0);
53     };
54     ($name:ident, $ty:expr, $nr:expr, $($v:ident),+) => {
55         $crate::ioctl_ioc_nr!($name, $crate::linux::ioctl::_IOC_NONE, $ty, $nr, 0, $($v),+);
56     };
57 }
58 
59 /// Declare an ioctl that reads data.
60 #[macro_export]
61 macro_rules! ioctl_ior_nr {
62     ($name:ident, $ty:expr, $nr:expr, $size:ty) => {
63         $crate::ioctl_ioc_nr!(
64             $name,
65             $crate::linux::ioctl::_IOC_READ,
66             $ty,
67             $nr,
68             ::std::mem::size_of::<$size>() as u32
69         );
70     };
71     ($name:ident, $ty:expr, $nr:expr, $size:ty, $($v:ident),+) => {
72         $crate::ioctl_ioc_nr!(
73             $name,
74             $crate::linux::ioctl::_IOC_READ,
75             $ty,
76             $nr,
77             ::std::mem::size_of::<$size>() as u32,
78             $($v),+
79         );
80     };
81 }
82 
83 /// Declare an ioctl that writes data.
84 #[macro_export]
85 macro_rules! ioctl_iow_nr {
86     ($name:ident, $ty:expr, $nr:expr, $size:ty) => {
87         $crate::ioctl_ioc_nr!(
88             $name,
89             $crate::linux::ioctl::_IOC_WRITE,
90             $ty,
91             $nr,
92             ::std::mem::size_of::<$size>() as u32
93         );
94     };
95     ($name:ident, $ty:expr, $nr:expr, $size:ty, $($v:ident),+) => {
96         $crate::ioctl_ioc_nr!(
97             $name,
98             $crate::linux::ioctl::_IOC_WRITE,
99             $ty,
100             $nr,
101             ::std::mem::size_of::<$size>() as u32,
102             $($v),+
103         );
104     };
105 }
106 
107 /// Declare an ioctl that reads and writes data.
108 #[macro_export]
109 macro_rules! ioctl_iowr_nr {
110     ($name:ident, $ty:expr, $nr:expr, $size:ty) => {
111         $crate::ioctl_ioc_nr!(
112             $name,
113             $crate::linux::ioctl::_IOC_READ | $crate::linux::ioctl::_IOC_WRITE,
114             $ty,
115             $nr,
116             ::std::mem::size_of::<$size>() as u32
117         );
118     };
119     ($name:ident, $ty:expr, $nr:expr, $size:ty, $($v:ident),+) => {
120         $crate::ioctl_ioc_nr!(
121             $name,
122             $crate::linux::ioctl::_IOC_READ | $crate::linux::ioctl::_IOC_WRITE,
123             $ty,
124             $nr,
125             ::std::mem::size_of::<$size>() as u32,
126             $($v),+
127         );
128     };
129 }
130 
131 pub const _IOC_NRBITS: c_uint = 8;
132 pub const _IOC_TYPEBITS: c_uint = 8;
133 pub const _IOC_SIZEBITS: c_uint = 14;
134 pub const _IOC_DIRBITS: c_uint = 2;
135 pub const _IOC_NRMASK: c_uint = 255;
136 pub const _IOC_TYPEMASK: c_uint = 255;
137 pub const _IOC_SIZEMASK: c_uint = 16383;
138 pub const _IOC_DIRMASK: c_uint = 3;
139 pub const _IOC_NRSHIFT: c_uint = 0;
140 pub const _IOC_TYPESHIFT: c_uint = 8;
141 pub const _IOC_SIZESHIFT: c_uint = 16;
142 pub const _IOC_DIRSHIFT: c_uint = 30;
143 pub const _IOC_NONE: c_uint = 0;
144 pub const _IOC_WRITE: c_uint = 1;
145 pub const _IOC_READ: c_uint = 2;
146 pub const IOC_IN: c_uint = 1_073_741_824;
147 pub const IOC_OUT: c_uint = 2_147_483_648;
148 pub const IOC_INOUT: c_uint = 3_221_225_472;
149 pub const IOCSIZE_MASK: c_uint = 1_073_676_288;
150 pub const IOCSIZE_SHIFT: c_uint = 16;
151 
152 #[cfg(any(target_os = "android", target_env = "musl"))]
153 pub type IoctlNr = c_int;
154 #[cfg(not(any(target_os = "android", target_env = "musl")))]
155 pub type IoctlNr = c_ulong;
156 
157 /// Run an ioctl with no arguments.
158 /// # Safety
159 /// The caller is responsible for determining the safety of the particular ioctl.
ioctl<F: AsRawDescriptor>(descriptor: &F, nr: IoctlNr) -> c_int160 pub unsafe fn ioctl<F: AsRawDescriptor>(descriptor: &F, nr: IoctlNr) -> c_int {
161     libc::ioctl(descriptor.as_raw_descriptor(), nr, 0)
162 }
163 
164 /// Run an ioctl with a single value argument.
165 /// # Safety
166 /// The caller is responsible for determining the safety of the particular ioctl.
ioctl_with_val(descriptor: &dyn AsRawDescriptor, nr: IoctlNr, arg: c_ulong) -> c_int167 pub unsafe fn ioctl_with_val(descriptor: &dyn AsRawDescriptor, nr: IoctlNr, arg: c_ulong) -> c_int {
168     libc::ioctl(descriptor.as_raw_descriptor(), nr, arg)
169 }
170 
171 /// Run an ioctl with an immutable reference.
172 /// # Safety
173 ///
174 /// The caller is responsible for determining the safety of the particular ioctl.
ioctl_with_ref<T>(descriptor: &dyn AsRawDescriptor, nr: IoctlNr, arg: &T) -> c_int175 pub unsafe fn ioctl_with_ref<T>(descriptor: &dyn AsRawDescriptor, nr: IoctlNr, arg: &T) -> c_int {
176     libc::ioctl(
177         descriptor.as_raw_descriptor(),
178         nr,
179         arg as *const T as *const c_void,
180     )
181 }
182 
183 /// Run an ioctl with a mutable reference.
184 /// # Safety
185 ///
186 /// The caller is responsible for determining the safety of the particular ioctl.
ioctl_with_mut_ref<T>( descriptor: &dyn AsRawDescriptor, nr: IoctlNr, arg: &mut T, ) -> c_int187 pub unsafe fn ioctl_with_mut_ref<T>(
188     descriptor: &dyn AsRawDescriptor,
189     nr: IoctlNr,
190     arg: &mut T,
191 ) -> c_int {
192     libc::ioctl(
193         descriptor.as_raw_descriptor(),
194         nr,
195         arg as *mut T as *mut c_void,
196     )
197 }
198 
199 /// Run an ioctl with a raw pointer.
200 /// # Safety
201 /// The caller is responsible for determining the safety of the particular ioctl.
ioctl_with_ptr<T>( descriptor: &dyn AsRawDescriptor, nr: IoctlNr, arg: *const T, ) -> c_int202 pub unsafe fn ioctl_with_ptr<T>(
203     descriptor: &dyn AsRawDescriptor,
204     nr: IoctlNr,
205     arg: *const T,
206 ) -> c_int {
207     libc::ioctl(descriptor.as_raw_descriptor(), nr, arg as *const c_void)
208 }
209 
210 /// Run an ioctl with a mutable raw pointer.
211 /// # Safety
212 /// The caller is responsible for determining the safety of the particular ioctl.
ioctl_with_mut_ptr<T>( descriptor: &dyn AsRawDescriptor, nr: IoctlNr, arg: *mut T, ) -> c_int213 pub unsafe fn ioctl_with_mut_ptr<T>(
214     descriptor: &dyn AsRawDescriptor,
215     nr: IoctlNr,
216     arg: *mut T,
217 ) -> c_int {
218     libc::ioctl(descriptor.as_raw_descriptor(), nr, arg as *mut c_void)
219 }
220 #[cfg(test)]
221 mod tests {
222     const TUNTAP: ::std::os::raw::c_uint = 0x54;
223     const VHOST: ::std::os::raw::c_uint = 0xaf;
224     const EVDEV: ::std::os::raw::c_uint = 0x45;
225 
226     ioctl_io_nr!(VHOST_SET_OWNER, VHOST, 0x01);
227     ioctl_ior_nr!(TUNGETFEATURES, TUNTAP, 0xcf, ::std::os::raw::c_uint);
228     ioctl_iow_nr!(TUNSETQUEUE, TUNTAP, 0xd9, ::std::os::raw::c_int);
229     ioctl_iowr_nr!(VHOST_GET_VRING_BASE, VHOST, 0x12, ::std::os::raw::c_int);
230 
231     ioctl_ior_nr!(EVIOCGBIT, EVDEV, 0x20 + evt, [u8; 128], evt);
232     ioctl_io_nr!(FAKE_IOCTL_2_ARG, EVDEV, 0x01 + x + y, x, y);
233 
234     #[test]
ioctl_macros()235     fn ioctl_macros() {
236         assert_eq!(0x0000af01, VHOST_SET_OWNER());
237         assert_eq!(0x800454cf, TUNGETFEATURES());
238         assert_eq!(0x400454d9, TUNSETQUEUE());
239         assert_eq!(0xc004af12, VHOST_GET_VRING_BASE());
240 
241         assert_eq!(0x80804522, EVIOCGBIT(2));
242         assert_eq!(0x00004509, FAKE_IOCTL_2_ARG(3, 5));
243     }
244 }
245