use bitvec::{field::BitField, order::Msb0, slice::BitSlice};
use crate::err::IpmiHeaderError;
use super::{
ipmi_v1_header::IpmiV1Header,
ipmi_v2_header::{IpmiV2Header, PayloadType},
};
#[derive(Clone, Copy, Debug)]
pub enum IpmiHeader {
V1_5(IpmiV1Header),
V2_0(IpmiV2Header),
}
impl TryFrom<&[u8]> for IpmiHeader {
type Error = IpmiHeaderError;
fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
if value.len() < 10 {
Err(IpmiHeaderError::WrongLength)?
}
let auth_type: AuthType = value[0].try_into()?;
match auth_type {
AuthType::RmcpPlus => Ok(IpmiHeader::V2_0(value.try_into()?)),
_ => Ok(IpmiHeader::V1_5(value.try_into()?)),
}
}
}
impl Into<Vec<u8>> for IpmiHeader {
fn into(self) -> Vec<u8> {
match self {
IpmiHeader::V1_5(header) => header.into(),
IpmiHeader::V2_0(header) => header.into(),
}
}
}
impl IpmiHeader {
pub fn payload_type(&self) -> PayloadType {
match self {
IpmiHeader::V1_5(_header) => PayloadType::IPMI,
IpmiHeader::V2_0(header) => header.payload_type,
}
}
pub fn header_len(first_byte: u8, second_byte: u8) -> Result<usize, IpmiHeaderError> {
let auth_type: AuthType = first_byte.try_into()?;
match auth_type {
AuthType::RmcpPlus => {
let length = 12;
let payload_type: PayloadType = BitSlice::<u8, Msb0>::from_element(&second_byte)
[3..]
.load::<u8>()
.try_into()?;
match payload_type {
PayloadType::OEM => Ok(length + 6),
_ => Ok(length),
}
}
AuthType::None => Ok(10),
_ => Ok(26),
}
}
pub fn payload_len(&self) -> usize {
match self {
IpmiHeader::V1_5(a) => a.payload_length.try_into().unwrap(),
IpmiHeader::V2_0(a) => a.payload_length.try_into().unwrap(),
}
}
}
#[derive(Clone, Copy, Debug)]
pub enum AuthType {
None,
MD2,
MD5,
PasswordOrKey,
OEM,
RmcpPlus,
}
impl TryFrom<u8> for AuthType {
type Error = IpmiHeaderError;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
0x00 => Ok(AuthType::None),
0x01 => Ok(AuthType::MD2),
0x02 => Ok(AuthType::MD5),
0x04 => Ok(AuthType::PasswordOrKey),
0x05 => Ok(AuthType::OEM),
0x06 => Ok(AuthType::RmcpPlus),
_ => Err(IpmiHeaderError::UnsupportedAuthType(value)),
}
}
}
impl Into<u8> for AuthType {
fn into(self) -> u8 {
match &self {
AuthType::None => 0x00,
AuthType::MD2 => 0x01,
AuthType::MD5 => 0x02,
AuthType::PasswordOrKey => 0x04,
AuthType::OEM => 0x05,
AuthType::RmcpPlus => 0x06,
}
}
}