11use deku:: { DekuContainerRead , DekuContainerWrite } ;
2- use log:: trace;
2+ use log:: { trace, warn } ;
33use pldm:: control:: { MultipartReceiveReq , MultipartReceiveResp } ;
44use pldm:: {
55 pldm_xfer_buf_async, proto_error, PldmError , PldmRequest , PldmResult ,
@@ -153,6 +153,9 @@ pub async fn df_read_with<F>(
153153where
154154 F : FnMut ( & [ u8 ] ) -> PldmResult < ( ) > ,
155155{
156+ // Maximum retries for the same offset. Avoids looping forever.
157+ const CRC_FAIL_RETRIES : usize = 20 ;
158+
156159 let req_offset = u32:: try_from ( offset) . map_err ( |_| {
157160 trace ! ( "invalid offset" ) ;
158161 PldmError :: InvalidArgument
@@ -177,6 +180,7 @@ where
177180 } ;
178181 let crc32 = crc:: Crc :: < u32 > :: new ( & crc:: CRC_32_ISO_HDLC ) ;
179182 let mut digest = crc32. digest ( ) ;
183+ let mut crc_fail_count = 0 ;
180184 loop {
181185 let mut tx_buf = [ 0 ; 18 ] ;
182186 let l = req. to_slice ( & mut tx_buf) . map_err ( |_| PldmError :: NoSpace ) ?;
@@ -205,13 +209,25 @@ where
205209
206210 let ( resp_data, resp_cs) = rest. split_at ( resp_data_len) ;
207211
208- digest. update ( resp_data) ;
212+ let mut up_digest = digest. clone ( ) ;
213+ up_digest. update ( resp_data) ;
209214 // unwrap: we have asserted the lengths above
210215 let cs = u32:: from_le_bytes ( resp_cs. try_into ( ) . unwrap ( ) ) ;
211216
212- if digest. clone ( ) . finalize ( ) != cs {
213- return Err ( proto_error ! ( "data checksum mismatch" ) ) ;
217+ if up_digest. clone ( ) . finalize ( ) != cs {
218+ warn ! (
219+ "data checksum mismatch requesting offset {}" ,
220+ req_offset as usize + part_offset
221+ ) ;
222+ crc_fail_count += 1 ;
223+ if crc_fail_count > CRC_FAIL_RETRIES {
224+ return Err ( proto_error ! ( "excess CRC failures" ) ) ;
225+ }
226+ req. xfer_op = pldm:: control:: xfer_op:: CURRENT_PART ;
227+ continue ;
214228 }
229+ digest = up_digest;
230+ crc_fail_count = 0 ;
215231
216232 // Ensure the host doesn't send more data than requested
217233 let total_len = part_offset
0 commit comments