Skip to main content

ipmi_rs_core/app/
get_channel_access.rs

1use crate::connection::{Channel, IpmiCommand, Message, NetFn, NotEnoughData};
2
3/// The Get Channel Access command.
4///
5/// This command is used to return whether a given channel is enabled or disabled,
6/// whether alerting is enabled or disabled for the entire channel, and under what
7/// system modes the channel can be accessed.
8///
9/// Reference: IPMI 2.0 Specification, Table 22-28
10pub struct GetChannelAccess {
11    channel: Channel,
12    access_type: ChannelAccessType,
13}
14
15impl GetChannelAccess {
16    /// Create a new Get Channel Access command for `channel`.
17    ///
18    /// Use `access_type` to specify whether to get the non-volatile or volatile
19    /// (currently active) settings.
20    pub fn new(channel: Channel, access_type: ChannelAccessType) -> Self {
21        Self {
22            channel,
23            access_type,
24        }
25    }
26
27    /// Create a command to get the non-volatile (persistent) access settings.
28    pub fn non_volatile(channel: Channel) -> Self {
29        Self::new(channel, ChannelAccessType::NonVolatile)
30    }
31
32    /// Create a command to get the volatile (active) access settings.
33    pub fn volatile(channel: Channel) -> Self {
34        Self::new(channel, ChannelAccessType::Volatile)
35    }
36}
37
38impl From<GetChannelAccess> for Message {
39    fn from(value: GetChannelAccess) -> Self {
40        let channel = value.channel.value() & 0x0F;
41        let access_type = match value.access_type {
42            ChannelAccessType::NonVolatile => 0x40, // 01b << 6
43            ChannelAccessType::Volatile => 0x80,    // 10b << 6
44        };
45        Message::new_request(NetFn::App, 0x41, vec![channel, access_type])
46    }
47}
48
49impl IpmiCommand for GetChannelAccess {
50    type Output = ChannelAccess;
51    type Error = NotEnoughData;
52
53    fn parse_success_response(data: &[u8]) -> Result<Self::Output, Self::Error> {
54        ChannelAccess::parse(data).ok_or(NotEnoughData)
55    }
56}
57
58/// Whether to get non-volatile or volatile channel access settings.
59#[derive(Clone, Copy, Debug, PartialEq)]
60pub enum ChannelAccessType {
61    /// Get non-volatile (persistent) settings stored in BMC.
62    NonVolatile,
63    /// Get volatile (currently active) settings.
64    Volatile,
65}
66
67/// Channel access information returned by the BMC.
68#[derive(Clone, Debug, PartialEq)]
69pub struct ChannelAccess {
70    /// The access mode for this channel.
71    pub access_mode: ChannelAccessMode,
72    /// Whether alerting is disabled for this channel.
73    pub alerting_disabled: bool,
74    /// Whether per-message authentication is disabled.
75    pub per_msg_auth_disabled: bool,
76    /// Whether user level authentication is disabled.
77    pub user_level_auth_disabled: bool,
78    /// The maximum privilege level allowed on this channel.
79    pub privilege_level_limit: ChannelPrivilegeLevel,
80}
81
82impl ChannelAccess {
83    /// Parse a `ChannelAccess` from IPMI response data.
84    ///
85    /// Reference: IPMI 2.0 Specification, Table 22-28
86    pub fn parse(data: &[u8]) -> Option<Self> {
87        if data.len() < 2 {
88            return None;
89        }
90
91        let access_mode = ChannelAccessMode::from(data[0] & 0x07);
92        let alerting_disabled = (data[0] & 0x20) == 0x20;
93        let per_msg_auth_disabled = (data[0] & 0x10) == 0x10;
94        let user_level_auth_disabled = (data[0] & 0x08) == 0x08;
95
96        let privilege_level_limit = ChannelPrivilegeLevel::from(data[1] & 0x0F);
97
98        Some(Self {
99            access_mode,
100            alerting_disabled,
101            per_msg_auth_disabled,
102            user_level_auth_disabled,
103            privilege_level_limit,
104        })
105    }
106
107    /// Returns true if the channel is disabled.
108    pub fn is_disabled(&self) -> bool {
109        matches!(self.access_mode, ChannelAccessMode::Disabled)
110    }
111}
112
113/// Channel access mode values.
114///
115/// Reference: IPMI 2.0 Specification, Table 6-4
116#[derive(Clone, Copy, Debug, PartialEq)]
117pub enum ChannelAccessMode {
118    /// The channel is disabled from being used to communicate with the BMC.
119    Disabled,
120    /// The channel is only available during pre-boot (before OS loads).
121    PreBootOnly,
122    /// The channel is always available for communication.
123    AlwaysAvailable,
124    /// The channel is in shared access mode.
125    Shared,
126    /// Unknown value.
127    Unknown(u8),
128}
129
130impl From<u8> for ChannelAccessMode {
131    fn from(value: u8) -> Self {
132        match value {
133            0x00 => Self::Disabled,
134            0x01 => Self::PreBootOnly,
135            0x02 => Self::AlwaysAvailable,
136            0x03 => Self::Shared,
137            v => Self::Unknown(v),
138        }
139    }
140}
141
142impl core::fmt::Display for ChannelAccessMode {
143    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
144        match self {
145            ChannelAccessMode::Disabled => write!(f, "Disabled"),
146            ChannelAccessMode::PreBootOnly => write!(f, "Pre-boot Only"),
147            ChannelAccessMode::AlwaysAvailable => write!(f, "Always Available"),
148            ChannelAccessMode::Shared => write!(f, "Shared"),
149            ChannelAccessMode::Unknown(value) => write!(f, "Unknown (0x{value:02X})"),
150        }
151    }
152}
153
154/// Channel privilege level values.
155///
156/// Reference: IPMI 2.0 Specification, Table 22-28
157#[derive(Clone, Copy, Debug, PartialEq)]
158pub enum ChannelPrivilegeLevel {
159    /// Reserved (invalid).
160    Reserved,
161    /// Callback privilege level.
162    Callback,
163    /// User privilege level.
164    User,
165    /// Operator privilege level.
166    Operator,
167    /// Administrator privilege level.
168    Administrator,
169    /// OEM proprietary privilege level.
170    Oem,
171    /// Unknown value.
172    Unknown(u8),
173}
174
175impl From<u8> for ChannelPrivilegeLevel {
176    fn from(value: u8) -> Self {
177        match value {
178            0x00 => Self::Reserved,
179            0x01 => Self::Callback,
180            0x02 => Self::User,
181            0x03 => Self::Operator,
182            0x04 => Self::Administrator,
183            0x05 => Self::Oem,
184            v => Self::Unknown(v),
185        }
186    }
187}
188
189impl core::fmt::Display for ChannelPrivilegeLevel {
190    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
191        match self {
192            ChannelPrivilegeLevel::Reserved => write!(f, "Reserved"),
193            ChannelPrivilegeLevel::Callback => write!(f, "Callback"),
194            ChannelPrivilegeLevel::User => write!(f, "User"),
195            ChannelPrivilegeLevel::Operator => write!(f, "Operator"),
196            ChannelPrivilegeLevel::Administrator => write!(f, "Administrator"),
197            ChannelPrivilegeLevel::Oem => write!(f, "OEM"),
198            ChannelPrivilegeLevel::Unknown(value) => write!(f, "Unknown (0x{value:02X})"),
199        }
200    }
201}