ipmi_rs/connection/impls/rmcp/
mod.rs1use crate::{connection::IpmiConnection, IpmiCommandError};
2use std::{net::ToSocketAddrs, time::Duration};
3
4mod socket;
5
6mod v1_5;
7pub use v1_5::{
8 ActivationError as V1_5ActivationError, ReadError as V1_5ReadError,
9 WriteError as V1_5WriteError,
10};
11
12mod v2_0;
13pub use v2_0::{
14 ActivationError as V2_0ActivationError, AuthenticationAlgorithm, ConfidentialityAlgorithm,
15 IntegrityAlgorithm, ReadError as V2_0ReadError, WriteError as V2_0WriteError, *,
16};
17
18mod checksum;
19
20mod header;
21pub(crate) use header::*;
22
23mod asf;
24pub(crate) use asf::*;
25
26mod internal;
27use internal::{Active, RmcpWithState, Unbound};
28
29#[derive(Debug)]
30pub enum RmcpIpmiReceiveError {
31 Io(std::io::Error),
32 RmcpHeader(RmcpHeaderError),
33 Session(UnwrapSessionError),
34 NotIpmi,
35 NotEnoughData,
36 EmptyMessage,
37 IpmbChecksumFailed,
38}
39
40#[derive(Debug)]
41pub enum RmcpIpmiSendError {
42 V1_5(V1_5WriteError),
43 V2_0(V2_0WriteError),
44}
45
46impl From<V1_5WriteError> for RmcpIpmiSendError {
47 fn from(value: V1_5WriteError) -> Self {
48 Self::V1_5(value)
49 }
50}
51
52impl From<V2_0WriteError> for RmcpIpmiSendError {
53 fn from(value: V2_0WriteError) -> Self {
54 Self::V2_0(value)
55 }
56}
57
58#[derive(Debug, Clone, PartialEq)]
59pub enum UnwrapSessionError {
60 V1_5(V1_5ReadError),
61 V2_0(V2_0ReadError),
62}
63
64impl From<V1_5ReadError> for UnwrapSessionError {
65 fn from(value: V1_5ReadError) -> Self {
66 Self::V1_5(value)
67 }
68}
69
70impl From<V2_0ReadError> for UnwrapSessionError {
71 fn from(value: V2_0ReadError) -> Self {
72 Self::V2_0(value)
73 }
74}
75
76#[derive(Debug)]
77pub enum RmcpIpmiError {
78 NotActive,
79 Receive(RmcpIpmiReceiveError),
80 Send(RmcpIpmiSendError),
81}
82
83impl From<RmcpIpmiReceiveError> for RmcpIpmiError {
84 fn from(value: RmcpIpmiReceiveError) -> Self {
85 Self::Receive(value)
86 }
87}
88
89impl From<RmcpIpmiSendError> for RmcpIpmiError {
90 fn from(value: RmcpIpmiSendError) -> Self {
91 Self::Send(value)
92 }
93}
94
95type CommandError<T> = IpmiCommandError<RmcpIpmiError, T>;
96
97#[derive(Debug)]
98pub enum ActivationError {
99 BindSocket(std::io::Error),
100 PingSend(std::io::Error),
101 PongReceive(std::io::Error),
102 PongRead,
103 IpmiNotSupported,
105 NoSupportedIpmiLANVersions,
106 GetChannelAuthenticationCapabilities(CommandError<()>),
107 V1_5(V1_5ActivationError),
108 V2_0(V2_0ActivationError),
109 RmcpError(RmcpHeaderError),
110}
111
112impl From<V1_5ActivationError> for ActivationError {
113 fn from(value: V1_5ActivationError) -> Self {
114 Self::V1_5(value)
115 }
116}
117
118impl From<V2_0ActivationError> for ActivationError {
119 fn from(value: V2_0ActivationError) -> Self {
120 Self::V2_0(value)
121 }
122}
123
124#[derive(Debug)]
125pub struct Rmcp {
126 unbound_state: RmcpWithState<Unbound>,
127 active_state: Option<RmcpWithState<Active>>,
128}
129
130impl Rmcp {
131 pub fn new<R>(remote: R, timeout: Duration) -> Result<Self, std::io::Error>
132 where
133 R: ToSocketAddrs + std::fmt::Debug,
134 {
135 let unbound_state = RmcpWithState::new(remote, timeout)?;
136
137 Ok(Self {
138 unbound_state,
139 active_state: None,
140 })
141 }
142
143 pub fn inactive_clone(&self) -> Self {
144 Self {
145 unbound_state: self.unbound_state.clone(),
146 active_state: None,
147 }
148 }
149
150 pub fn is_active(&self) -> bool {
151 self.active_state.is_some()
152 }
153
154 pub fn activate(
159 &mut self,
160 rmcp_plus: bool,
161 username: Option<&str>,
162 password: Option<&[u8]>,
163 ) -> Result<(), ActivationError> {
164 if self.active_state.take().is_some() {
165 log::info!("De-activating RMCP connection for re-activation");
167 }
168
169 let inactive = self
170 .unbound_state
171 .bind()
172 .map_err(ActivationError::BindSocket)?;
173
174 let activated = inactive.activate(rmcp_plus, username, password)?;
175 self.active_state = Some(activated);
176 Ok(())
177 }
178}
179
180impl IpmiConnection for Rmcp {
181 type SendError = RmcpIpmiError;
182
183 type RecvError = RmcpIpmiError;
184
185 type Error = RmcpIpmiError;
186
187 fn send(&mut self, request: &mut crate::connection::Request) -> Result<(), Self::SendError> {
188 let active = self.active_state.as_mut().ok_or(RmcpIpmiError::NotActive)?;
189 active.send(request)
190 }
191
192 fn recv(&mut self) -> Result<crate::connection::Response, Self::RecvError> {
193 let active = self.active_state.as_mut().ok_or(RmcpIpmiError::NotActive)?;
194 active.recv().map_err(RmcpIpmiError::Receive)
195 }
196
197 fn send_recv(
198 &mut self,
199 request: &mut crate::connection::Request,
200 ) -> Result<crate::connection::Response, Self::Error> {
201 let active = self.active_state.as_mut().ok_or(RmcpIpmiError::NotActive)?;
202 active.send_recv(request)
203 }
204}