Skip to content

Commit 2492e09

Browse files
committed
pldm-platform: Return an iterator from get_pdr()
This now returns an iterator over all PDRs on a responder. Signed-off-by: Matt Johnston <matt@codeconstruct.com.au>
1 parent d33e583 commit 2492e09

File tree

3 files changed

+125
-64
lines changed

3 files changed

+125
-64
lines changed

pldm-platform-util/src/bin/pldm-platform.rs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -126,11 +126,7 @@ struct PdrRepositoryCommand {}
126126

127127
#[derive(FromArgs, Debug)]
128128
#[argh(subcommand, name = "get-pdr", description = "Get PDR")]
129-
struct GetPdrCommand {
130-
/// PDR record
131-
#[argh(positional)]
132-
record: u32,
133-
}
129+
struct GetPdrCommand {}
134130

135131
fn enable_command_op(op_state: &str) -> Result<SetSensorOperationalState> {
136132
Ok(if op_state.starts_with("en") {
@@ -243,10 +239,15 @@ async fn async_main() -> anyhow::Result<()> {
243239
let pdr_info = get_pdr_repository_info(&mut ep).await?;
244240
println!("PDR Repository Info: {pdr_info:#x?}");
245241
}
246-
Command::GetPdr(s) => {
242+
Command::GetPdr(_) => {
247243
let mut ep = args.addr.create_req_async()?;
248-
let pdr = get_pdr(&mut ep, s.record).await?;
249-
println!("PDR: {pdr:#x?}");
244+
let mut p = get_pdr(&mut ep);
245+
while let Some(r) = p.next().await {
246+
match r {
247+
Ok(pdr) => println!("PDR: {pdr:#x?}"),
248+
Err(e) => println!("Error fetching PDR: {e}"),
249+
}
250+
}
250251
}
251252
}
252253
Ok(())

pldm-platform/src/proto.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -598,7 +598,7 @@ pub enum PdrRecord {
598598
}
599599

600600
impl PdrRecord {
601-
fn pdr_type(&self) -> u8 {
601+
pub fn pdr_type(&self) -> u8 {
602602
match self {
603603
Self::FileDescriptor(_) => 30,
604604
}

pldm-platform/src/requester.rs

Lines changed: 115 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ pub async fn set_simple_state_sensor_enables(
212212
Ok(())
213213
}
214214

215+
/// Get PDR Repository Info
215216
pub async fn get_pdr_repository_info(
216217
comm: &mut impl mctp::AsyncReqChannel,
217218
) -> Result<GetPDRRepositoryInfoResp> {
@@ -237,68 +238,127 @@ pub async fn get_pdr_repository_info(
237238
Ok(ret)
238239
}
239240

240-
pub async fn get_pdr(
241-
comm: &mut impl mctp::AsyncReqChannel,
242-
record_handle: u32,
243-
) -> Result<PdrRecord> {
244-
// TODO: callers pass a buffer? might be nice to
245-
// reuse between tx/rx.
246-
let mut rxbuf = [0; 200];
247-
248-
let getpdr = GetPDRReq {
249-
record_handle,
250-
data_transfer_handle: 0,
251-
transfer_operation_flag: TransferOperationFlag::FirstPart,
252-
// subtract 4 bytes pldm header, 12 bytes PDR header/crc
253-
request_count: (rxbuf.len() - 4 - 12) as u16,
254-
record_change_number: 0,
255-
};
256-
let mut txdata = [0; 50];
257-
let l = getpdr.to_slice(&mut txdata)?;
258-
let txdata = &txdata[..l];
259-
let req = PldmRequest::new_borrowed(
260-
PLDM_TYPE_PLATFORM,
261-
Cmd::GetPDR as u8,
262-
txdata,
263-
);
264-
265-
let resp = pldm_xfer_buf_async(comm, req, &mut rxbuf).await?;
266-
let ((rest, _), pdrrsp) =
267-
GetPDRResp::from_bytes((&resp.data, 0)).map_err(|e| {
268-
trace!("GetPDR parse error {e:?}");
269-
proto_error!("Bad GetPDR response")
270-
})?;
271-
if !rest.is_empty() {
272-
return Err(proto_error!("Extra response"));
273-
}
241+
/// An iterator over PDR records, returned by [`get_pdr`].
242+
pub struct GetPdrIter<'a, C: mctp::AsyncReqChannel> {
243+
next_handle: u32,
244+
done: bool,
245+
comm: &'a mut C,
246+
}
274247

275-
if pdrrsp.transfer_flag != xfer_flag::START_AND_END {
276-
return Err(proto_error!("Can't handle multipart"));
248+
impl<'a, C: mctp::AsyncReqChannel> GetPdrIter<'a, C> {
249+
fn new(comm: &'a mut C) -> Self {
250+
Self {
251+
next_handle: 0,
252+
done: false,
253+
comm,
254+
}
277255
}
278256

279-
let ((rest, _), pdr) =
280-
Pdr::from_bytes((&pdrrsp.record_data, 0)).map_err(|e| {
281-
trace!("GetSensorReading parse error {e}");
282-
proto_error!("Bad GetSensorReading response")
283-
})?;
284-
if !rest.is_empty() {
285-
return Err(proto_error!("Extra PDR response"));
257+
/// Return the next PDR from the host.
258+
///
259+
/// `None` will be returned after the last record.
260+
/// `Some(Err)` may be returned on error, further calls to next() may still
261+
/// return more records successfully.
262+
pub async fn next(&mut self) -> Option<Result<PdrRecord>> {
263+
self.next_inner().await.transpose()
286264
}
287265

288-
if pdr.record_handle != record_handle {
289-
return Err(proto_error!("PDR record handle mismatch"));
290-
}
291-
if pdr.pdr_header_version != PDR_VERSION_1 {
292-
return Err(proto_error!("PDR unknown version"));
293-
}
266+
// Inner function to use `?`.
267+
async fn next_inner(&mut self) -> Result<Option<PdrRecord>> {
268+
if self.done {
269+
return Ok(None);
270+
}
294271

295-
let expect_len = pdrrsp.record_data.len() - 10;
296-
if pdr.data_length as usize != expect_len {
297-
warn!(
298-
"Incorrect PDR data_length, got {}, expect {}",
299-
pdr.data_length, expect_len
272+
// TODO: callers pass a buffer? might be nice to
273+
// reuse between tx/rx.
274+
let mut rxbuf = [0; 200];
275+
276+
let getpdr = GetPDRReq {
277+
record_handle: self.next_handle,
278+
data_transfer_handle: 0,
279+
transfer_operation_flag: TransferOperationFlag::FirstPart,
280+
// subtract 4 bytes pldm header, 12 bytes PDR header/crc
281+
request_count: (rxbuf.len() - 4 - 12) as u16,
282+
record_change_number: 0,
283+
};
284+
let mut txdata = [0; 13];
285+
let l = getpdr.to_slice(&mut txdata)?;
286+
let txdata = &txdata[..l];
287+
let req = PldmRequest::new_borrowed(
288+
PLDM_TYPE_PLATFORM,
289+
Cmd::GetPDR as u8,
290+
txdata,
300291
);
292+
293+
// Failure prior to parsing a next_handle should stop the iterator,
294+
// setting self.done and returning the failure Result.
295+
// Other errors don't stop the iterator, they are just returned as a Result.
296+
297+
let resp = pldm_xfer_buf_async(self.comm, req, &mut rxbuf)
298+
.await
299+
.inspect_err(|_| self.done = true)?;
300+
let ((rest, _), pdrrsp) = GetPDRResp::from_bytes((&resp.data, 0))
301+
.map_err(|e| {
302+
trace!("GetPDR parse error {e:?}");
303+
self.done = true;
304+
proto_error!("Bad GetPDR response")
305+
})?;
306+
if !rest.is_empty() {
307+
self.done = true;
308+
return Err(proto_error!("Extra response"));
309+
}
310+
311+
if pdrrsp.next_record_handle == 0 {
312+
// Last handle
313+
self.done = true
314+
}
315+
self.next_handle = pdrrsp.next_record_handle;
316+
317+
if pdrrsp.record_data.len() > getpdr.request_count as usize {
318+
return Err(proto_error!(
319+
"Get PDR returned extra record data",
320+
"Requested {}, got {}",
321+
getpdr.request_count,
322+
pdrrsp.record_data.len()
323+
));
324+
}
325+
326+
// This is a current limitation of this implementation,
327+
// not a problem with the response. We can't attempt
328+
// to parse the record_data since it will be incomplete.
329+
if pdrrsp.transfer_flag != xfer_flag::START_AND_END {
330+
return Err(proto_error!("Can't handle multipart"));
331+
}
332+
333+
let ((rest, _), pdr) = Pdr::from_bytes((&pdrrsp.record_data, 0))
334+
.map_err(|e| {
335+
trace!("GetPDR parse error {e}");
336+
proto_error!("Bad GetPDR response")
337+
})?;
338+
if !rest.is_empty() {
339+
return Err(proto_error!("Extra PDR response"));
340+
}
341+
342+
let expect_len = pdrrsp.record_data.len() - 10;
343+
if pdr.data_length as usize != expect_len {
344+
warn!(
345+
"Incorrect PDR data_length, got {}, expect {}",
346+
pdr.data_length, expect_len
347+
);
348+
}
349+
350+
if pdr.pdr_header_version != PDR_VERSION_1 {
351+
return Err(proto_error!("PDR unknown version"));
352+
}
353+
354+
Ok(Some(pdr.record))
301355
}
356+
}
302357

303-
Ok(pdr.record)
358+
/// Return a `GetPdrIter` to iterate over Get PDR requests.
359+
pub fn get_pdr<C>(comm: &mut C) -> GetPdrIter<'_, C>
360+
where
361+
C: mctp::AsyncReqChannel,
362+
{
363+
GetPdrIter::new(comm)
304364
}

0 commit comments

Comments
 (0)