@@ -3,7 +3,7 @@ use r_efi::protocols::tcp4;
33
44use crate :: io;
55use crate :: net:: SocketAddrV4 ;
6- use crate :: ptr:: NonNull ;
6+ use crate :: ptr:: { self , NonNull } ;
77use crate :: sync:: atomic:: { AtomicBool , Ordering } ;
88use crate :: sys:: pal:: helpers;
99use crate :: time:: { Duration , Instant } ;
@@ -12,20 +12,21 @@ const TYPE_OF_SERVICE: u8 = 8;
1212const TIME_TO_LIVE : u8 = 255 ;
1313
1414pub ( crate ) struct Tcp4 {
15+ handle : NonNull < crate :: ffi:: c_void > ,
1516 protocol : NonNull < tcp4:: Protocol > ,
1617 flag : AtomicBool ,
17- #[ expect( dead_code) ]
1818 service_binding : helpers:: ServiceProtocol ,
1919}
2020
2121const DEFAULT_ADDR : efi:: Ipv4Address = efi:: Ipv4Address { addr : [ 0u8 ; 4 ] } ;
2222
2323impl Tcp4 {
2424 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 ) ?;
2728
28- Ok ( Self { service_binding, protocol, flag : AtomicBool :: new ( false ) } )
29+ Ok ( Self { service_binding, handle , protocol, flag : AtomicBool :: new ( false ) } )
2930 }
3031
3132 pub ( crate ) fn configure (
@@ -42,11 +43,14 @@ impl Tcp4 {
4243 ( DEFAULT_ADDR , 0 )
4344 } ;
4445
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) ;
5054
5155 let mut config_data = tcp4:: ConfigData {
5256 type_of_service : TYPE_OF_SERVICE ,
@@ -60,7 +64,7 @@ impl Tcp4 {
6064 station_port,
6165 subnet_mask,
6266 } ,
63- control_option : crate :: ptr:: null_mut ( ) ,
67+ control_option : ptr:: null_mut ( ) ,
6468 } ;
6569
6670 let r = unsafe { ( ( * protocol) . configure ) ( protocol, & mut config_data) } ;
@@ -74,17 +78,55 @@ impl Tcp4 {
7478 let r = unsafe {
7579 ( ( * protocol) . get_mode_data ) (
7680 protocol,
77- crate :: ptr:: null_mut ( ) ,
81+ ptr:: null_mut ( ) ,
7882 & 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 ( ) ,
8286 )
8387 } ;
8488
8589 if r. is_error ( ) { Err ( io:: Error :: from_raw_os_error ( r. as_usize ( ) ) ) } else { Ok ( config_data) }
8690 }
8791
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+
88130 pub ( crate ) fn connect ( & self , timeout : Option < Duration > ) -> io:: Result < ( ) > {
89131 let evt = unsafe { self . create_evt ( ) } ?;
90132 let completion_token =
@@ -263,6 +305,12 @@ impl Tcp4 {
263305 }
264306}
265307
308+ impl Drop for Tcp4 {
309+ fn drop ( & mut self ) {
310+ let _ = unsafe { self . service_binding . destroy_child ( self . handle ) } ;
311+ }
312+ }
313+
266314extern "efiapi" fn toggle_atomic_flag ( _: r_efi:: efi:: Event , ctx : * mut crate :: ffi:: c_void ) {
267315 let flag = unsafe { AtomicBool :: from_ptr ( ctx. cast ( ) ) } ;
268316 flag. store ( true , Ordering :: Relaxed ) ;
0 commit comments