ipmi_rs/connection/
mod.rs1mod completion_code;
2use std::num::NonZeroU8;
3
4pub use completion_code::CompletionCode;
5
6mod impls;
7
8#[cfg(feature = "unix-file")]
9pub use impls::File;
10
11pub use impls::rmcp;
12
13mod netfn;
14pub use netfn::NetFn;
15
16mod request;
17pub use request::{Request, RequestTargetAddress};
18
19mod response;
20pub use response::Response;
21
22#[derive(Copy, Clone, Debug, PartialEq)]
23pub struct Address(pub u8);
24
25#[derive(Copy, Clone, Debug, PartialEq)]
26pub struct ChannelNumber(NonZeroU8);
27
28impl ChannelNumber {
29 pub fn new(value: NonZeroU8) -> Option<Self> {
33 if value.get() <= 0xB {
34 Some(Self(value))
35 } else {
36 None
37 }
38 }
39
40 pub fn value(&self) -> NonZeroU8 {
45 self.0
46 }
47}
48
49#[derive(Copy, Clone, Debug, PartialEq)]
50pub enum Channel {
51 Primary,
52 Numbered(ChannelNumber),
53 System,
54 Current,
55}
56
57impl Channel {
58 pub fn new(value: u8) -> Option<Self> {
62 match value {
63 0 => Some(Self::Primary),
64 0xE => Some(Self::Current),
65 0xF => Some(Self::System),
66 v => Some(Self::Numbered(ChannelNumber::new(NonZeroU8::new(v)?)?)),
67 }
68 }
69
70 pub fn value(&self) -> u8 {
76 match self {
77 Channel::Primary => 0x0,
78 Channel::Numbered(v) => v.value().get(),
79 Channel::Current => 0xE,
80 Channel::System => 0xF,
81 }
82 }
83}
84
85impl core::fmt::Display for Channel {
86 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
87 match self {
88 Channel::Primary => write!(f, "Primary channel"),
89 Channel::Numbered(number) => write!(f, "Channel 0x{:01X}", number.value()),
90 Channel::Current => write!(f, "Current channel"),
91 Channel::System => write!(f, "System channel"),
92 }
93 }
94}
95
96#[derive(Clone, Copy, Debug, PartialEq)]
97pub enum LogicalUnit {
98 Zero,
99 One,
100 Two,
101 Three,
102}
103
104impl LogicalUnit {
105 pub fn from_low_bits(value: u8) -> Self {
108 let value = value & 0b11;
109
110 match value {
111 0b00 => Self::Zero,
112 0b01 => Self::One,
113 0b10 => Self::Two,
114 0b11 => Self::Three,
115 _ => unreachable!("Value bitmasked with 0b11 has value greater than 3"),
116 }
117 }
118}
119
120impl TryFrom<u8> for LogicalUnit {
121 type Error = ();
122
123 fn try_from(value: u8) -> Result<Self, Self::Error> {
124 if value <= 0b11 {
125 Ok(Self::from_low_bits(value))
126 } else {
127 Err(())
128 }
129 }
130}
131
132impl LogicalUnit {
133 pub fn value(&self) -> u8 {
134 match self {
135 LogicalUnit::Zero => 0,
136 LogicalUnit::One => 1,
137 LogicalUnit::Two => 2,
138 LogicalUnit::Three => 3,
139 }
140 }
141}
142
143pub trait IpmiConnection {
144 type SendError: core::fmt::Debug;
145 type RecvError: core::fmt::Debug;
146 type Error: core::fmt::Debug + From<Self::SendError> + From<Self::RecvError>;
147
148 fn send(&mut self, request: &mut Request) -> Result<(), Self::SendError>;
149 fn recv(&mut self) -> Result<Response, Self::RecvError>;
150 fn send_recv(&mut self, request: &mut Request) -> Result<Response, Self::Error>;
151}
152
153#[derive(Clone, Debug, PartialEq)]
154pub struct Message {
155 netfn: u8,
156 cmd: u8,
157 data: Vec<u8>,
158}
159
160impl Message {
161 pub fn new_request(netfn: NetFn, cmd: u8, data: Vec<u8>) -> Self {
162 Self {
163 netfn: netfn.request_value(),
164 cmd,
165 data,
166 }
167 }
168
169 pub fn new_response(netfn: NetFn, cmd: u8, data: Vec<u8>) -> Self {
170 Self {
171 netfn: netfn.response_value(),
172 cmd,
173 data,
174 }
175 }
176
177 pub fn new_raw(netfn: u8, cmd: u8, data: Vec<u8>) -> Self {
178 Self { netfn, cmd, data }
179 }
180
181 pub fn netfn(&self) -> NetFn {
182 NetFn::from(self.netfn)
183 }
184
185 pub fn netfn_raw(&self) -> u8 {
186 self.netfn
187 }
188
189 pub fn cmd(&self) -> u8 {
190 self.cmd
191 }
192
193 pub fn data(&self) -> &[u8] {
194 &self.data
195 }
196
197 pub fn data_mut(&mut self) -> &mut [u8] {
198 &mut self.data
199 }
200}
201
202#[derive(Clone, Copy, Debug, PartialEq)]
203pub enum ParseResponseError<T> {
204 Failed(CompletionCode),
205 NotEnoughData,
206 Parse(T),
207}
208
209impl<T> From<T> for ParseResponseError<T> {
210 fn from(value: T) -> Self {
211 Self::Parse(value)
212 }
213}
214
215pub trait IpmiCommand: Into<Message> {
216 type Output;
217 type Error;
218
219 fn parse_response(
220 completion_code: CompletionCode,
221 data: &[u8],
222 ) -> Result<Self::Output, ParseResponseError<Self::Error>>;
223
224 fn check_cc_success(cc: CompletionCode) -> Result<(), ParseResponseError<Self::Error>> {
225 if cc.is_success() {
226 Ok(())
227 } else {
228 Err(ParseResponseError::Failed(cc))
229 }
230 }
231
232 fn target(&self) -> Option<(Address, Channel)> {
233 None
234 }
235}