Skip to main content

ipmi_rs_core/app/
get_channel_info.rs

1use crate::connection::{Channel, IpmiCommand, Message, NetFn, NotEnoughData};
2
3/// The Get Channel Info command.
4///
5/// Reference: IPMI 2.0 Specification, Table 22-29
6pub struct GetChannelInfo {
7    channel: Channel,
8}
9
10impl GetChannelInfo {
11    /// Create a new Get Channel Info command for `channel`.
12    pub fn new(channel: Channel) -> Self {
13        Self { channel }
14    }
15}
16
17impl From<GetChannelInfo> for Message {
18    fn from(value: GetChannelInfo) -> Self {
19        let channel = value.channel.value() & 0x0F;
20        Message::new_request(NetFn::App, 0x42, vec![channel])
21    }
22}
23
24impl IpmiCommand for GetChannelInfo {
25    type Output = ChannelInfo;
26    type Error = NotEnoughData;
27
28    fn parse_success_response(data: &[u8]) -> Result<Self::Output, Self::Error> {
29        ChannelInfo::parse(data).ok_or(NotEnoughData)
30    }
31}
32
33/// Channel info returned by the BMC.
34#[derive(Clone, Debug, PartialEq)]
35pub struct ChannelInfo {
36    pub channel: Channel,
37    pub medium_type: ChannelMediumType,
38    pub protocol_type: ChannelProtocolType,
39    pub session_support: ChannelSessionSupport,
40    pub active_sessions: u8,
41    pub vendor_id: u32,
42    pub aux_info: AuxChannelInfo,
43}
44
45impl ChannelInfo {
46    /// Parse a `ChannelInfo` from IPMI response data.
47    ///
48    /// Reference: IPMI 2.0 Specification, Table 22-29
49    pub fn parse(data: &[u8]) -> Option<Self> {
50        if data.len() < 9 {
51            return None;
52        }
53
54        let channel_raw = data[0] & 0x0F;
55        let channel = Channel::new(channel_raw)?;
56
57        let medium_type = ChannelMediumType::from(data[1] & 0x7F);
58        let protocol_type = ChannelProtocolType::from(data[2] & 0x1F);
59
60        let session_support = ChannelSessionSupport::from((data[3] >> 6) & 0x03);
61        let active_sessions = data[3] & 0x3F;
62
63        let vendor_id = u32::from_le_bytes([data[4], data[5], data[6], 0]);
64        let aux_info = AuxChannelInfo {
65            byte1: data[7],
66            byte2: data[8],
67        };
68
69        Some(Self {
70            channel,
71            medium_type,
72            protocol_type,
73            session_support,
74            active_sessions,
75            vendor_id,
76            aux_info,
77        })
78    }
79}
80
81/// Auxiliary channel information bytes.
82#[derive(Clone, Copy, Debug, PartialEq)]
83pub struct AuxChannelInfo {
84    pub byte1: u8,
85    pub byte2: u8,
86}
87
88/// Channel medium type values.
89///
90/// Reference: IPMI 2.0 Specification, Table 6-3
91#[derive(Clone, Copy, Debug, PartialEq)]
92pub enum ChannelMediumType {
93    Reserved,
94    Ipmb,
95    IcmbV1_0,
96    IcmbV0_9,
97    Lan802_3,
98    AsynchSerialModem,
99    OtherLan,
100    PciSmbus,
101    SmbusV1_0,
102    SmbusV2_0,
103    Usb1X,
104    Usb2X,
105    SystemInterface,
106    Oem(u8),
107    ReservedValue(u8),
108}
109
110impl From<u8> for ChannelMediumType {
111    fn from(value: u8) -> Self {
112        match value {
113            0x00 => Self::Reserved,
114            0x01 => Self::Ipmb,
115            0x02 => Self::IcmbV1_0,
116            0x03 => Self::IcmbV0_9,
117            0x04 => Self::Lan802_3,
118            0x05 => Self::AsynchSerialModem,
119            0x06 => Self::OtherLan,
120            0x07 => Self::PciSmbus,
121            0x08 => Self::SmbusV1_0,
122            0x09 => Self::SmbusV2_0,
123            0x0A => Self::Usb1X,
124            0x0B => Self::Usb2X,
125            0x0C => Self::SystemInterface,
126            0x60..=0x7F => Self::Oem(value),
127            _ => Self::ReservedValue(value),
128        }
129    }
130}
131
132impl core::fmt::Display for ChannelMediumType {
133    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
134        match self {
135            ChannelMediumType::Reserved => write!(f, "Reserved"),
136            ChannelMediumType::Ipmb => write!(f, "IPMB (I2C)"),
137            ChannelMediumType::IcmbV1_0 => write!(f, "ICMB v1.0"),
138            ChannelMediumType::IcmbV0_9 => write!(f, "ICMB v0.9"),
139            ChannelMediumType::Lan802_3 => write!(f, "802.3 LAN"),
140            ChannelMediumType::AsynchSerialModem => write!(f, "Asynchronous Serial/Modem"),
141            ChannelMediumType::OtherLan => write!(f, "Other LAN"),
142            ChannelMediumType::PciSmbus => write!(f, "PCI SMBus"),
143            ChannelMediumType::SmbusV1_0 => write!(f, "SMBus v1.0/1.1"),
144            ChannelMediumType::SmbusV2_0 => write!(f, "SMBus v2.0"),
145            ChannelMediumType::Usb1X => write!(f, "USB 1.x (reserved)"),
146            ChannelMediumType::Usb2X => write!(f, "USB 2.x (reserved)"),
147            ChannelMediumType::SystemInterface => write!(f, "System Interface"),
148            ChannelMediumType::Oem(value) => write!(f, "OEM (0x{value:02X})"),
149            ChannelMediumType::ReservedValue(value) => write!(f, "Reserved (0x{value:02X})"),
150        }
151    }
152}
153
154/// Channel protocol type values.
155///
156/// Reference: IPMI 2.0 Specification, Table 6-2
157#[derive(Clone, Copy, Debug, PartialEq)]
158pub enum ChannelProtocolType {
159    Reserved,
160    IpmbV1_0,
161    IcmbV1_0,
162    IpmiSmbus,
163    Kcs,
164    Smic,
165    Bt10,
166    Bt15,
167    TerminalMode,
168    Oem(u8),
169    ReservedValue(u8),
170}
171
172impl From<u8> for ChannelProtocolType {
173    fn from(value: u8) -> Self {
174        match value {
175            0x00 => Self::Reserved,
176            0x01 => Self::IpmbV1_0,
177            0x02 => Self::IcmbV1_0,
178            0x04 => Self::IpmiSmbus,
179            0x05 => Self::Kcs,
180            0x06 => Self::Smic,
181            0x07 => Self::Bt10,
182            0x08 => Self::Bt15,
183            0x09 => Self::TerminalMode,
184            0x1C..=0x1F => Self::Oem(value),
185            _ => Self::ReservedValue(value),
186        }
187    }
188}
189
190impl core::fmt::Display for ChannelProtocolType {
191    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
192        match self {
193            ChannelProtocolType::Reserved => write!(f, "Reserved"),
194            ChannelProtocolType::IpmbV1_0 => write!(f, "IPMB-1.0"),
195            ChannelProtocolType::IcmbV1_0 => write!(f, "ICMB-1.0"),
196            ChannelProtocolType::IpmiSmbus => write!(f, "IPMI-SMBus"),
197            ChannelProtocolType::Kcs => write!(f, "KCS"),
198            ChannelProtocolType::Smic => write!(f, "SMIC"),
199            ChannelProtocolType::Bt10 => write!(f, "BT-10"),
200            ChannelProtocolType::Bt15 => write!(f, "BT-15"),
201            ChannelProtocolType::TerminalMode => write!(f, "Terminal Mode"),
202            ChannelProtocolType::Oem(value) => write!(f, "OEM (0x{value:02X})"),
203            ChannelProtocolType::ReservedValue(value) => write!(f, "Reserved (0x{value:02X})"),
204        }
205    }
206}
207
208/// Session support for a channel.
209#[derive(Clone, Copy, Debug, PartialEq)]
210pub enum ChannelSessionSupport {
211    Sessionless,
212    SingleSession,
213    MultiSession,
214    SessionBased,
215    Reserved(u8),
216}
217
218impl From<u8> for ChannelSessionSupport {
219    fn from(value: u8) -> Self {
220        match value {
221            0x00 => Self::Sessionless,
222            0x01 => Self::SingleSession,
223            0x02 => Self::MultiSession,
224            0x03 => Self::SessionBased,
225            v => Self::Reserved(v),
226        }
227    }
228}
229
230impl core::fmt::Display for ChannelSessionSupport {
231    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
232        match self {
233            ChannelSessionSupport::Sessionless => write!(f, "Session-less"),
234            ChannelSessionSupport::SingleSession => write!(f, "Single-session"),
235            ChannelSessionSupport::MultiSession => write!(f, "Multi-session"),
236            ChannelSessionSupport::SessionBased => write!(f, "Session-based"),
237            ChannelSessionSupport::Reserved(value) => write!(f, "Reserved (0x{value:02X})"),
238        }
239    }
240}