11use r_efi:: efi:: { self , Status } ;
22use r_efi:: protocols:: tcp4;
33
4- use crate :: io;
4+ use crate :: io:: { self , IoSlice } ;
55use crate :: net:: SocketAddrV4 ;
66use crate :: ptr:: NonNull ;
77use crate :: sync:: atomic:: { AtomicBool , Ordering } ;
@@ -108,11 +108,7 @@ impl Tcp4 {
108108 }
109109
110110 pub ( crate ) fn write ( & self , buf : & [ u8 ] , timeout : Option < Duration > ) -> io:: Result < usize > {
111- let evt = unsafe { self . create_evt ( ) } ?;
112- let completion_token =
113- tcp4:: CompletionToken { event : evt. as_ptr ( ) , status : Status :: SUCCESS } ;
114111 let data_len = u32:: try_from ( buf. len ( ) ) . unwrap_or ( u32:: MAX ) ;
115-
116112 let fragment = tcp4:: FragmentData {
117113 fragment_length : data_len,
118114 fragment_buffer : buf. as_ptr ( ) . cast :: < crate :: ffi:: c_void > ( ) . cast_mut ( ) ,
@@ -125,14 +121,58 @@ impl Tcp4 {
125121 fragment_table : [ fragment] ,
126122 } ;
127123
128- let protocol = self . protocol . as_ptr ( ) ;
129- let mut token = tcp4:: IoToken {
130- completion_token,
131- packet : tcp4:: IoTokenPacket {
132- tx_data : ( & raw mut tx_data) . cast :: < tcp4:: TransmitData < 0 > > ( ) ,
133- } ,
124+ self . write_inner ( ( & raw mut tx_data) . cast ( ) , timeout) . map ( |_| data_len as usize )
125+ }
126+
127+ pub ( crate ) fn write_vectored (
128+ & self ,
129+ buf : & [ IoSlice < ' _ > ] ,
130+ timeout : Option < Duration > ,
131+ ) -> io:: Result < usize > {
132+ let mut data_len = 0u32 ;
133+ let mut fragment_count = 0u32 ;
134+
135+ // Calculate how many IoSlice in buf can be transmitted.
136+ for i in buf {
137+ // IoSlice length is always <= u32::MAX in UEFI.
138+ match data_len. checked_add ( i. as_slice ( ) . len ( ) as u32 ) {
139+ Some ( x) => data_len = x,
140+ None => break ,
141+ }
142+ fragment_count += 1 ;
143+ }
144+
145+ let tx_data_size = size_of :: < tcp4:: TransmitData < 0 > > ( )
146+ + size_of :: < tcp4:: FragmentData > ( ) * ( fragment_count as usize ) ;
147+ let mut tx_data = helpers:: UefiBox :: < tcp4:: TransmitData > :: new ( tx_data_size) ;
148+ unsafe {
149+ ( * tx_data. as_mut_ptr ( ) ) . push = r_efi:: efi:: Boolean :: FALSE ;
150+ ( * tx_data. as_mut_ptr ( ) ) . urgent = r_efi:: efi:: Boolean :: FALSE ;
151+ ( * tx_data. as_mut_ptr ( ) ) . data_length = data_len;
152+ ( * tx_data. as_mut_ptr ( ) ) . fragment_count = fragment_count;
153+ // SAFETY: IoSlice and FragmentData are guaranteed to have same layout.
154+ crate :: ptr:: copy_nonoverlapping (
155+ buf. as_ptr ( ) . cast ( ) ,
156+ ( * tx_data. as_mut_ptr ( ) ) . fragment_table . as_mut_ptr ( ) ,
157+ fragment_count as usize ,
158+ ) ;
134159 } ;
135160
161+ self . write_inner ( tx_data. as_mut_ptr ( ) , timeout) . map ( |_| data_len as usize )
162+ }
163+
164+ fn write_inner (
165+ & self ,
166+ tx_data : * mut tcp4:: TransmitData ,
167+ timeout : Option < Duration > ,
168+ ) -> io:: Result < ( ) > {
169+ let evt = unsafe { self . create_evt ( ) } ?;
170+ let completion_token =
171+ tcp4:: CompletionToken { event : evt. as_ptr ( ) , status : Status :: SUCCESS } ;
172+
173+ let protocol = self . protocol . as_ptr ( ) ;
174+ let mut token = tcp4:: IoToken { completion_token, packet : tcp4:: IoTokenPacket { tx_data } } ;
175+
136176 let r = unsafe { ( ( * protocol) . transmit ) ( protocol, & mut token) } ;
137177 if r. is_error ( ) {
138178 return Err ( io:: Error :: from_raw_os_error ( r. as_usize ( ) ) ) ;
@@ -143,7 +183,7 @@ impl Tcp4 {
143183 if completion_token. status . is_error ( ) {
144184 Err ( io:: Error :: from_raw_os_error ( completion_token. status . as_usize ( ) ) )
145185 } else {
146- Ok ( data_len as usize )
186+ Ok ( ( ) )
147187 }
148188 }
149189
0 commit comments