@@ -5,49 +5,43 @@ use alloc::sync::Arc;
5
5
use alloc:: vec:: Vec ;
6
6
use core:: fmt:: Debug ;
7
7
8
+ use bitfield_struct:: bitfield;
9
+
8
10
use crate :: fd:: { AccessPermission , ObjectInterface } ;
9
11
use crate :: fs:: { NodeKind , VfsNode } ;
10
12
use crate :: io;
11
13
12
- #[ derive( Copy , Clone ) ]
13
- pub struct IoCtlCall ( pub u32 ) ;
14
-
15
- impl Debug for IoCtlCall {
16
- fn fmt ( & self , f : & mut core:: fmt:: Formatter < ' _ > ) -> core:: fmt:: Result {
17
- f. debug_struct ( "IoCtlCall" )
18
- . field ( "call_nr" , & self . call_nr ( ) )
19
- . field ( "call_type" , & self . call_type ( ) )
20
- . field ( "call_size" , & self . call_size ( ) )
21
- . field ( "call_dir" , & self . call_dir ( ) )
22
- . field ( ".0" , & self . 0 )
23
- . finish ( )
24
- }
14
+ /// Encoding for an IOCTL command, as done in the Linux Kernel.
15
+ ///
16
+ /// See [relevant kernel header](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/asm-generic/ioctl.h?h=v6.15) for reference.
17
+ ///
18
+ /// The goal of this interface is to easily support linux applications that communicate via IOCTL,
19
+ /// so linux compatibility is an intended and explicit goal here.
20
+ #[ bitfield( u32 ) ]
21
+ pub struct IoCtlCall {
22
+ call_nr : u8 ,
23
+
24
+ call_type : u8 ,
25
+
26
+ #[ bits( 2 , from = IoCtlDirection :: from_bits_truncate, default = IoCtlDirection :: empty( ) ) ]
27
+ call_dir : IoCtlDirection ,
28
+
29
+ #[ bits( 14 ) ]
30
+ call_size : u16 ,
25
31
}
26
32
27
33
bitflags ! {
28
- #[ derive( Debug , Copy , Clone , Default ) ]
34
+ #[ derive( Debug , Copy , Clone , Default , PartialEq , Eq ) ]
29
35
pub struct IoCtlDirection : u8 {
30
36
const IOC_WRITE = 1 ;
31
37
const IOC_READ = 2 ;
32
38
}
33
39
}
34
40
35
- impl IoCtlCall {
36
- pub fn call_nr ( & self ) -> u8 {
37
- ( self . 0 & 0xff ) as u8
38
- }
39
-
40
- pub fn call_type ( & self ) -> u8 {
41
- ( ( self . 0 >> 8 ) & 0xff ) as u8
42
- }
43
-
44
- pub fn call_dir ( & self ) -> IoCtlDirection {
45
- let dir = ( self . 0 >> 30 ) & 0x3 ;
46
- IoCtlDirection :: from_bits_truncate ( dir as u8 )
47
- }
48
-
49
- pub fn call_size ( & self ) -> u16 {
50
- ( ( self . 0 >> 16 ) & 0x3fff ) as u16
41
+ impl IoCtlDirection {
42
+ // Required for IoCtlCall
43
+ const fn into_bits ( self ) -> u8 {
44
+ self . bits ( )
51
45
}
52
46
}
53
47
@@ -94,3 +88,48 @@ pub(crate) fn register_ioctl(path: &str, ioctl_object: Arc<dyn ObjectInterface>)
94
88
. traverse_mount ( & mut path, Box :: new ( IoCtlNode ( ioctl_object) ) )
95
89
. expect ( "Failed to mount ioctl: filesystem error" ) ;
96
90
}
91
+
92
+ #[ cfg( test) ]
93
+ mod tests {
94
+ use crate :: fs:: ioctl:: { IoCtlCall , IoCtlDirection } ;
95
+
96
+ #[ test_case]
97
+ fn ioctl_call_correctly_written ( ) {
98
+ let call_nr = 0x12u8 ;
99
+ let call_type = 0x78u8 ;
100
+ let call_dir = IoCtlDirection :: IOC_WRITE ;
101
+ let call_size = 0x423u16 ;
102
+
103
+ let ioctl_call_number = ( u32:: from ( call_size) << 18 )
104
+ | ( u32:: from ( call_dir. bits ( ) ) << 16 )
105
+ | ( u32:: from ( call_type) << 8 )
106
+ | u32:: from ( call_nr) ;
107
+
108
+ let call = IoCtlCall :: new ( )
109
+ . with_call_nr ( call_nr)
110
+ . with_call_type ( call_type)
111
+ . with_call_dir ( call_dir)
112
+ . with_call_size ( call_size) ;
113
+
114
+ assert_eq ! ( ioctl_call_number, call. into_bits( ) ) ;
115
+ }
116
+ #[ test_case]
117
+ fn ioctl_call_correctly_parsed ( ) {
118
+ let call_nr = 0x12u8 ;
119
+ let call_type = 0x78u8 ;
120
+ let call_dir = IoCtlDirection :: IOC_WRITE ;
121
+ let call_size = 0x423u16 ;
122
+
123
+ let ioctl_call_number = ( u32:: from ( call_size) << 18 )
124
+ | ( u32:: from ( call_dir. bits ( ) ) << 16 )
125
+ | ( u32:: from ( call_type) << 8 )
126
+ | u32:: from ( call_nr) ;
127
+
128
+ let parsed = IoCtlCall :: from_bits ( ioctl_call_number) ;
129
+
130
+ assert_eq ! ( call_nr, parsed. call_nr( ) ) ;
131
+ assert_eq ! ( call_type, parsed. call_type( ) ) ;
132
+ assert_eq ! ( call_dir, parsed. call_dir( ) ) ;
133
+ assert_eq ! ( call_size, parsed. call_size( ) ) ;
134
+ }
135
+ }
0 commit comments