use std::io::ErrorKind;
use clap::Parser;
use common::CommonOpts;
use ipmi_rs::connection::RequestTargetAddress;
use ipmi_rs::rmcp::{
RmcpIpmiError, RmcpIpmiReceiveError, RmcpIpmiSendError, V1_5WriteError, V2_0WriteError,
};
use ipmi_rs::{
connection::Message,
connection::{IpmiConnection, LogicalUnit, Request},
};
mod common;
#[derive(Parser)]
pub struct Command {
#[clap(flatten)]
common: CommonOpts,
#[clap(required = true)]
message: Vec<String>,
}
fn try_parse_message(input: &[u8]) -> std::io::Result<Message> {
if input.len() < 2 {
let err = std::io::Error::new(
std::io::ErrorKind::InvalidInput,
"Need at least 2 bytes of input".to_string(),
);
return Err(err);
}
let cmd = input[1];
let data = input[2..].to_vec();
Ok(Message::new_raw(input[0], cmd, data))
}
fn main() -> std::io::Result<()> {
pretty_env_logger::formatted_builder()
.parse_filters(&std::env::var("RUST_LOG").unwrap_or("info".to_string()))
.init();
let command = Command::parse();
let mut data = Vec::new();
for arg in command.message {
let u8_value = u8::from_str_radix(&arg, 16).map_err(|_| {
let err = std::io::Error::new(
std::io::ErrorKind::InvalidInput,
format!("Could not parse '{arg}' as hex integer"),
);
err
})?;
data.push(u8_value);
}
let message = try_parse_message(&data)?;
let mut request: Request = Request::new(message, RequestTargetAddress::Bmc(LogicalUnit::Zero));
let ipmi = command.common.get_connection()?;
let result = match ipmi {
common::IpmiConnectionEnum::Rmcp(mut r) => {
r.inner_mut().send_recv(&mut request).map_err(|e| match e {
RmcpIpmiError::Receive(RmcpIpmiReceiveError::Io(io))
| RmcpIpmiError::Send(RmcpIpmiSendError::V1_5(V1_5WriteError::Io(io)))
| RmcpIpmiError::Send(RmcpIpmiSendError::V2_0(V2_0WriteError::Io(io))) => io,
e => {
log::error!("RMCP command failed: {e:?}");
std::io::Error::new(ErrorKind::Other, format!("{e:?}"))
}
})?
}
common::IpmiConnectionEnum::File(mut f) => f.inner_mut().send_recv(&mut request)?,
};
println!("Response:");
println!("Completion code: 0x{:02X}", result.cc());
println!("NetFN: 0x{:02X} ({:?})", result.netfn_raw(), result.netfn());
println!("Cmd: 0x{:02X}", result.cmd());
println!("Data: {:02X?}", result.data());
Ok(())
}