1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
mod completion_code;
pub use completion_code::CompletionCode;

mod impls;

#[cfg(feature = "unix-file")]
pub use impls::File;

pub use impls::rmcp;

mod netfn;
pub use netfn::NetFn;

mod request;
pub use request::Request;

mod response;
pub use response::Response;

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum LogicalUnit {
    Zero,
    One,
    Two,
    Three,
}

impl TryFrom<u8> for LogicalUnit {
    type Error = ();

    fn try_from(value: u8) -> Result<Self, Self::Error> {
        let val = match value {
            0 => Self::Zero,
            1 => Self::One,
            2 => Self::Two,
            3 => Self::Three,
            _ => return Err(()),
        };
        Ok(val)
    }
}

impl LogicalUnit {
    pub fn value(&self) -> u8 {
        match self {
            LogicalUnit::Zero => 0,
            LogicalUnit::One => 1,
            LogicalUnit::Two => 2,
            LogicalUnit::Three => 3,
        }
    }
}

pub trait IpmiConnection {
    type SendError: core::fmt::Debug;
    type RecvError: core::fmt::Debug;
    type Error: core::fmt::Debug + From<Self::SendError> + From<Self::RecvError>;

    fn send(&mut self, request: &mut Request) -> Result<(), Self::SendError>;
    fn recv(&mut self) -> Result<Response, Self::RecvError>;
    fn send_recv(&mut self, request: &mut Request) -> Result<Response, Self::Error>;
}

#[derive(Clone, Debug, PartialEq)]
pub struct Message {
    netfn: u8,
    cmd: u8,
    data: Vec<u8>,
}

impl Message {
    pub fn new_request(netfn: NetFn, cmd: u8, data: Vec<u8>) -> Self {
        Self {
            netfn: netfn.request_value(),
            cmd,
            data,
        }
    }

    pub fn new_response(netfn: NetFn, cmd: u8, data: Vec<u8>) -> Self {
        Self {
            netfn: netfn.response_value(),
            cmd,
            data,
        }
    }

    pub fn new_raw(netfn: u8, cmd: u8, data: Vec<u8>) -> Self {
        Self { netfn, cmd, data }
    }

    pub fn netfn(&self) -> NetFn {
        NetFn::from(self.netfn)
    }

    pub fn netfn_raw(&self) -> u8 {
        self.netfn
    }

    pub fn cmd(&self) -> u8 {
        self.cmd
    }

    pub fn data(&self) -> &[u8] {
        &self.data
    }

    pub fn data_mut(&mut self) -> &mut [u8] {
        &mut self.data
    }
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum ParseResponseError<T> {
    Failed(CompletionCode),
    NotEnoughData,
    Parse(T),
}

impl<T> From<T> for ParseResponseError<T> {
    fn from(value: T) -> Self {
        Self::Parse(value)
    }
}

pub trait IpmiCommand: Into<Message> {
    type Output;
    type Error;

    fn parse_response(
        completion_code: CompletionCode,
        data: &[u8],
    ) -> Result<Self::Output, ParseResponseError<Self::Error>>;

    fn check_cc_success(cc: CompletionCode) -> Result<(), ParseResponseError<Self::Error>> {
        if cc.is_success() {
            Ok(())
        } else {
            Err(ParseResponseError::Failed(cc))
        }
    }
}