@@ -3,7 +3,7 @@ use r_efi::protocols::tcp4;
3
3
4
4
use crate :: io;
5
5
use crate :: net:: SocketAddrV4 ;
6
- use crate :: ptr:: NonNull ;
6
+ use crate :: ptr:: { self , NonNull } ;
7
7
use crate :: sync:: atomic:: { AtomicBool , Ordering } ;
8
8
use crate :: sys:: pal:: helpers;
9
9
use crate :: time:: { Duration , Instant } ;
@@ -12,20 +12,21 @@ const TYPE_OF_SERVICE: u8 = 8;
12
12
const TIME_TO_LIVE : u8 = 255 ;
13
13
14
14
pub ( crate ) struct Tcp4 {
15
+ handle : NonNull < crate :: ffi:: c_void > ,
15
16
protocol : NonNull < tcp4:: Protocol > ,
16
17
flag : AtomicBool ,
17
- #[ expect( dead_code) ]
18
18
service_binding : helpers:: ServiceProtocol ,
19
19
}
20
20
21
21
const DEFAULT_ADDR : efi:: Ipv4Address = efi:: Ipv4Address { addr : [ 0u8 ; 4 ] } ;
22
22
23
23
impl Tcp4 {
24
24
pub ( crate ) fn new ( ) -> io:: Result < Self > {
25
- let service_binding = helpers:: ServiceProtocol :: open ( tcp4:: SERVICE_BINDING_PROTOCOL_GUID ) ?;
26
- let protocol = helpers:: open_protocol ( service_binding. child_handle ( ) , tcp4:: PROTOCOL_GUID ) ?;
25
+ let ( service_binding, handle) =
26
+ helpers:: ServiceProtocol :: open ( tcp4:: SERVICE_BINDING_PROTOCOL_GUID ) ?;
27
+ let protocol = helpers:: open_protocol ( handle, tcp4:: PROTOCOL_GUID ) ?;
27
28
28
- Ok ( Self { service_binding, protocol, flag : AtomicBool :: new ( false ) } )
29
+ Ok ( Self { service_binding, handle , protocol, flag : AtomicBool :: new ( false ) } )
29
30
}
30
31
31
32
pub ( crate ) fn configure (
@@ -42,11 +43,14 @@ impl Tcp4 {
42
43
( DEFAULT_ADDR , 0 )
43
44
} ;
44
45
45
- // FIXME: Remove when passive connections with proper subnet handling are added
46
- assert ! ( station_address. is_none( ) ) ;
47
- let use_default_address = efi:: Boolean :: TRUE ;
48
- let ( station_address, station_port) = ( DEFAULT_ADDR , 0 ) ;
49
- let subnet_mask = helpers:: ipv4_to_r_efi ( crate :: net:: Ipv4Addr :: new ( 0 , 0 , 0 , 0 ) ) ;
46
+ let use_default_address: r_efi:: efi:: Boolean = station_address. is_none ( ) . into ( ) ;
47
+ let ( station_address, station_port) = if let Some ( x) = station_address {
48
+ ( helpers:: ipv4_to_r_efi ( * x. ip ( ) ) , x. port ( ) )
49
+ } else {
50
+ ( DEFAULT_ADDR , 0 )
51
+ } ;
52
+ let subnet_mask = crate :: net:: Ipv4Addr :: new ( 255 , 255 , 255 , 0 ) ;
53
+ let subnet_mask = helpers:: ipv4_to_r_efi ( subnet_mask) ;
50
54
51
55
let mut config_data = tcp4:: ConfigData {
52
56
type_of_service : TYPE_OF_SERVICE ,
@@ -60,7 +64,7 @@ impl Tcp4 {
60
64
station_port,
61
65
subnet_mask,
62
66
} ,
63
- control_option : crate :: ptr:: null_mut ( ) ,
67
+ control_option : ptr:: null_mut ( ) ,
64
68
} ;
65
69
66
70
let r = unsafe { ( ( * protocol) . configure ) ( protocol, & mut config_data) } ;
@@ -74,17 +78,55 @@ impl Tcp4 {
74
78
let r = unsafe {
75
79
( ( * protocol) . get_mode_data ) (
76
80
protocol,
77
- crate :: ptr:: null_mut ( ) ,
81
+ ptr:: null_mut ( ) ,
78
82
& mut config_data,
79
- crate :: ptr:: null_mut ( ) ,
80
- crate :: ptr:: null_mut ( ) ,
81
- crate :: ptr:: null_mut ( ) ,
83
+ ptr:: null_mut ( ) ,
84
+ ptr:: null_mut ( ) ,
85
+ ptr:: null_mut ( ) ,
82
86
)
83
87
} ;
84
88
85
89
if r. is_error ( ) { Err ( io:: Error :: from_raw_os_error ( r. as_usize ( ) ) ) } else { Ok ( config_data) }
86
90
}
87
91
92
+ pub ( crate ) fn accept ( & self ) -> io:: Result < Self > {
93
+ let evt = unsafe { self . create_evt ( ) } ?;
94
+ let completion_token =
95
+ tcp4:: CompletionToken { event : evt. as_ptr ( ) , status : Status :: SUCCESS } ;
96
+ let mut listen_token =
97
+ tcp4:: ListenToken { completion_token, new_child_handle : ptr:: null_mut ( ) } ;
98
+
99
+ let protocol = self . protocol . as_ptr ( ) ;
100
+ let r = unsafe { ( ( * protocol) . accept ) ( protocol, & mut listen_token) } ;
101
+ if r. is_error ( ) {
102
+ return Err ( io:: Error :: from_raw_os_error ( r. as_usize ( ) ) ) ;
103
+ }
104
+
105
+ unsafe { self . wait_or_cancel ( None , & mut listen_token. completion_token ) } ?;
106
+
107
+ if completion_token. status . is_error ( ) {
108
+ Err ( io:: Error :: from_raw_os_error ( completion_token. status . as_usize ( ) ) )
109
+ } else {
110
+ // EDK2 internals seem to assume a single ServiceBinding Protocol for TCP4 and TCP6, and
111
+ // thus does not use any service binding protocol data in destroying child sockets. It
112
+ // does seem to suggest that we need to cleanup even the protocols created by accept. To
113
+ // be on the safe side with other implementations, we will be using the same service
114
+ // binding protocol as the parent TCP4 handle.
115
+ //
116
+ // https://github.com/tianocore/edk2/blob/f80580f56b267c96f16f985dbf707b2f96947da4/NetworkPkg/TcpDxe/TcpDriver.c#L938
117
+
118
+ let handle = NonNull :: new ( listen_token. new_child_handle ) . unwrap ( ) ;
119
+ let protocol = helpers:: open_protocol ( handle, tcp4:: PROTOCOL_GUID ) ?;
120
+
121
+ Ok ( Self {
122
+ handle,
123
+ service_binding : self . service_binding ,
124
+ protocol,
125
+ flag : AtomicBool :: new ( false ) ,
126
+ } )
127
+ }
128
+ }
129
+
88
130
pub ( crate ) fn connect ( & self , timeout : Option < Duration > ) -> io:: Result < ( ) > {
89
131
let evt = unsafe { self . create_evt ( ) } ?;
90
132
let completion_token =
@@ -263,6 +305,12 @@ impl Tcp4 {
263
305
}
264
306
}
265
307
308
+ impl Drop for Tcp4 {
309
+ fn drop ( & mut self ) {
310
+ let _ = self . service_binding . destroy_child ( self . handle ) ;
311
+ }
312
+ }
313
+
266
314
extern "efiapi" fn toggle_atomic_flag ( _: r_efi:: efi:: Event , ctx : * mut crate :: ffi:: c_void ) {
267
315
let flag = unsafe { AtomicBool :: from_ptr ( ctx. cast ( ) ) } ;
268
316
flag. store ( true , Ordering :: Relaxed ) ;
0 commit comments