use core::fmt;
use bitvec::{field::BitField, order::Msb0, slice::BitSlice};
use crate::err::{IpmiPayloadError, LunError};
use super::ipmi_payload_request::IpmiPayloadRequest;
use super::ipmi_payload_response::IpmiPayloadResponse;
#[derive(Clone)]
pub enum IpmiPayload {
Request(IpmiPayloadRequest),
Response(IpmiPayloadResponse),
}
impl TryFrom<&[u8]> for IpmiPayload {
type Error = IpmiPayloadError;
fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
if value.len() < 7 {
Err(IpmiPayloadError::WrongLength)?
}
let netfn_rqlun: &BitSlice<u8, Msb0> = BitSlice::<u8, Msb0>::from_element(&value[1]);
let netfn = netfn_rqlun[0..6].load::<u8>();
let command_type: CommandType = netfn.into();
match command_type {
CommandType::Request => Ok(IpmiPayload::Request(value.try_into()?)),
CommandType::Response => Ok(IpmiPayload::Response(value.try_into()?)),
}
}
}
impl Into<Vec<u8>> for IpmiPayload {
fn into(self) -> Vec<u8> {
match self {
IpmiPayload::Request(payload) => payload.into(),
_ => todo!(), }
}
}
#[derive(Clone, Copy, Debug)]
pub enum NetFn {
Chassis,
Bridge,
SensorEvent,
App,
Firmware,
Storage,
Transport,
Reserved,
Unknown(u8),
}
impl fmt::Display for NetFn {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
NetFn::Chassis => write!(f, "Chassis"),
NetFn::Bridge => write!(f, "Bridge"),
NetFn::SensorEvent => write!(f, "Sensor Event"),
NetFn::App => write!(f, "App"),
NetFn::Firmware => write!(f, "Firmware"),
NetFn::Storage => write!(f, "Storage"),
NetFn::Transport => write!(f, "Transport"),
NetFn::Reserved => write!(f, "Reserved"),
NetFn::Unknown(x) => write!(f, "Unknown: {}", x),
}
}
}
impl From<u8> for NetFn {
fn from(value: u8) -> Self {
match value {
0x00..=0x01 => NetFn::Chassis,
0x02..=0x03 => NetFn::Bridge,
0x04..=0x05 => NetFn::SensorEvent,
0x06..=0x07 => NetFn::App,
0x08..=0x09 => NetFn::Firmware,
0x0A..=0x0B => NetFn::Storage,
0x0C..=0x0D => NetFn::Transport,
0x0E..=0x2B => NetFn::Reserved,
_ => NetFn::Unknown(value), }
}
}
impl NetFn {
pub fn to_u8(&self, command_type: CommandType) -> u8 {
match self {
NetFn::Chassis => match command_type {
CommandType::Request => 0x00,
CommandType::Response => 0x01,
},
NetFn::Bridge => match command_type {
CommandType::Request => 0x02,
CommandType::Response => 0x03,
},
NetFn::SensorEvent => match command_type {
CommandType::Request => 0x04,
CommandType::Response => 0x05,
},
NetFn::App => match command_type {
CommandType::Request => 0x06,
CommandType::Response => 0x07,
},
NetFn::Firmware => match command_type {
CommandType::Request => 0x08,
CommandType::Response => 0x09,
},
NetFn::Storage => match command_type {
CommandType::Request => 0x0A,
CommandType::Response => 0x0B,
},
NetFn::Transport => match command_type {
CommandType::Request => 0x0C,
CommandType::Response => 0x0D,
},
NetFn::Reserved => match command_type {
CommandType::Request => 0x0E,
CommandType::Response => 0x2B,
},
NetFn::Unknown(fn_code) => match command_type {
CommandType::Request => *fn_code,
CommandType::Response => *fn_code,
},
}
}
}
pub enum CommandType {
Request,
Response,
}
impl From<u8> for CommandType {
fn from(value: u8) -> Self {
if value % 2 == 0 {
CommandType::Request
} else {
CommandType::Response
}
}
}
#[derive(Clone, Debug)]
pub enum Lun {
Bmc,
Oem1,
Sms,
Oem2,
}
impl fmt::Display for Lun {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Lun::Bmc => write!(f, "BMC"),
Lun::Oem1 => write!(f, "OEM1"),
Lun::Sms => write!(f, "SMS"),
Lun::Oem2 => write!(f, "OEM2"),
}
}
}
impl TryFrom<u8> for Lun {
type Error = LunError;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
0b00 => Ok(Lun::Bmc),
0b01 => Ok(Lun::Oem1),
0b10 => Ok(Lun::Sms),
0b11 => Ok(Lun::Oem2),
_ => Err(LunError::UnknownLun(value)),
}
}
}
impl Into<u8> for Lun {
fn into(self) -> u8 {
match self {
Lun::Bmc => 0b00,
Lun::Oem1 => 0b01,
Lun::Sms => 0b10,
Lun::Oem2 => 0b11,
}
}
}
pub enum AddrType {
SlaveAddress,
SoftwareId,
}
impl From<bool> for AddrType {
fn from(value: bool) -> Self {
match value {
false => AddrType::SlaveAddress,
true => AddrType::SoftwareId,
}
}
}
impl Into<u8> for AddrType {
fn into(self) -> u8 {
match self {
AddrType::SlaveAddress => 0,
AddrType::SoftwareId => 2,
}
}
}
#[derive(Clone, Debug)]
pub enum SoftwareType {
Bios,
SmiHandler,
SystemManagementSoftware,
Oem,
RemoteConsoleSoftware(u8),
TerminalModeRemoteConsole,
Reserved(u8),
}
impl fmt::Display for SoftwareType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
SoftwareType::Bios => write!(f, "BIOS"),
SoftwareType::SmiHandler => write!(f, "SMI Handler"),
SoftwareType::SystemManagementSoftware => write!(f, "System Management Software"),
SoftwareType::Oem => write!(f, "OEM"),
SoftwareType::RemoteConsoleSoftware(x) => write!(f, "Remote Console Software: {}", x),
SoftwareType::TerminalModeRemoteConsole => write!(f, "Terminal Mode Remote Console"),
SoftwareType::Reserved(x) => write!(f, "Reserved: {}", x),
}
}
}
impl From<u8> for SoftwareType {
fn from(value: u8) -> Self {
match value {
0x00..=0x0F => SoftwareType::Bios,
0x10..=0x1F => SoftwareType::SmiHandler,
0x20..=0x2F => SoftwareType::SystemManagementSoftware,
0x30..=0x3F => SoftwareType::Oem,
0x40..=0x46 => SoftwareType::RemoteConsoleSoftware(value - 0x3F),
0x47 => SoftwareType::TerminalModeRemoteConsole,
_ => SoftwareType::Reserved(value),
}
}
}
impl Into<u8> for SoftwareType {
fn into(self) -> u8 {
match self {
SoftwareType::Bios => 0x00,
SoftwareType::SmiHandler => 0x10,
SoftwareType::SystemManagementSoftware => 0x20,
SoftwareType::Oem => 0x30,
SoftwareType::RemoteConsoleSoftware(a) => a,
SoftwareType::TerminalModeRemoteConsole => 0x47,
SoftwareType::Reserved(a) => a,
}
}
}
#[derive(Clone, Debug)]
pub enum SlaveAddress {
Bmc,
Unknown(u8),
}
impl fmt::Display for SlaveAddress {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
SlaveAddress::Bmc => write!(f, "BMC"),
SlaveAddress::Unknown(x) => write!(f, "Unknown: {}", x),
}
}
}
impl From<u8> for SlaveAddress {
fn from(value: u8) -> Self {
match value {
0x20 => SlaveAddress::Bmc,
_ => SlaveAddress::Unknown(value),
}
}
}
impl Into<u8> for SlaveAddress {
fn into(self) -> u8 {
match self {
SlaveAddress::Bmc => 0x20,
SlaveAddress::Unknown(a) => a,
}
}
}