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