ipmi_rs/connection/impls/rmcp/v2_0/messages/
rakp_2.rs

1use std::num::NonZeroU32;
2
3use super::RakpErrorStatusCode;
4
5#[derive(Debug)]
6pub enum ParseError {
7    NotEnoughData,
8    ErrorStatusCode(ErrorStatusCode),
9    UnknownErrorStatusCode(u8),
10    InvalidRemoteConsoleSessionId,
11}
12
13#[derive(Debug, PartialEq)]
14pub struct RakpMessage2<'a> {
15    pub message_tag: u8,
16    pub remote_console_session_id: NonZeroU32,
17    pub managed_system_random_number: [u8; 16],
18    pub managed_system_guid: [u8; 16],
19    pub key_exchange_auth_code: &'a [u8],
20}
21
22impl<'a> RakpMessage2<'a> {
23    pub fn from_data(data: &'a [u8]) -> Result<Self, ParseError> {
24        // 4 = tag, status code, reserved bytes
25        if data.len() < 4 {
26            return Err(ParseError::NotEnoughData);
27        }
28
29        let message_tag = data[0];
30        let status_code = data[2];
31
32        if status_code != 0 {
33            return Err(ErrorStatusCode::try_from(status_code)
34                .map(ParseError::ErrorStatusCode)
35                .unwrap_or(ParseError::UnknownErrorStatusCode(status_code)));
36        }
37
38        if data.len() < 40 {
39            return Err(ParseError::NotEnoughData);
40        }
41
42        let remote_console_session_id =
43            if let Some(v) = NonZeroU32::new(u32::from_le_bytes(data[4..8].try_into().unwrap())) {
44                v
45            } else {
46                return Err(ParseError::InvalidRemoteConsoleSessionId);
47            };
48
49        let managed_system_random_number = data[8..24].try_into().unwrap();
50        let managed_system_guid = data[24..40].try_into().unwrap();
51        let key_exchange_auth_code = &data[40..];
52
53        Ok(Self {
54            message_tag,
55            remote_console_session_id,
56            managed_system_random_number,
57            managed_system_guid,
58            key_exchange_auth_code,
59        })
60    }
61}
62
63#[derive(Debug, Clone, Copy, PartialEq)]
64#[repr(u8)]
65pub enum ErrorStatusCode {
66    Common(RakpErrorStatusCode),
67    InactiveSessionId = 0x08,
68    InvalidRole = 0x09,
69    UnauthorizedRoleOrPrivilegeLevelRequested = 0x0A,
70    InsufficientResourcesToCreateSessionAtRequestedRole = 0x0B,
71    InvalidNameLength = 0x0C,
72    UnauthorizedName = 0x0D,
73}
74
75impl TryFrom<u8> for ErrorStatusCode {
76    type Error = ();
77
78    fn try_from(value: u8) -> Result<Self, Self::Error> {
79        if let Ok(common) = TryFrom::try_from(value) {
80            return Ok(ErrorStatusCode::Common(common));
81        }
82
83        let value = match value {
84            0x03 => ErrorStatusCode::InactiveSessionId,
85            0x09 => ErrorStatusCode::InvalidRole,
86            0x0A => ErrorStatusCode::UnauthorizedRoleOrPrivilegeLevelRequested,
87            0x0B => ErrorStatusCode::InsufficientResourcesToCreateSessionAtRequestedRole,
88            0x0C => ErrorStatusCode::InvalidNameLength,
89            0x0D => ErrorStatusCode::UnauthorizedName,
90            _ => return Err(()),
91        };
92
93        Ok(value)
94    }
95}
96
97#[test]
98pub fn from_data() {
99    let data = [
100        0x00, 0x00, 0x00, 0x00, 0xa4, 0xa3, 0xa2, 0xa0, 0xe8, 0x2c, 0x00, 0x00, 0x42, 0x72, 0x00,
101        0x00, 0x59, 0x18, 0x00, 0x00, 0xac, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
102        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6b, 0x61, 0xba, 0x25, 0xc8,
103        0x22, 0x4e, 0x32, 0x78, 0x63, 0x62, 0x6b, 0x30, 0x7c, 0x8d, 0xc8, 0x15, 0x22, 0x90, 0x91,
104    ];
105
106    let message = RakpMessage2::from_data(&data).unwrap();
107
108    let expected = RakpMessage2 {
109        message_tag: 0x00,
110        remote_console_session_id: NonZeroU32::new(0xa0a2a3a4).unwrap(),
111        managed_system_random_number: [
112            0xe8, 0x2c, 0x00, 0x00, 0x42, 0x72, 0x00, 0x00, 0x59, 0x18, 0x00, 0x00, 0xac, 0x04,
113            0x00, 0x00,
114        ],
115        managed_system_guid: [
116            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
117            0x00, 0x00,
118        ],
119        key_exchange_auth_code: &[
120            0x6b, 0x61, 0xba, 0x25, 0xc8, 0x22, 0x4e, 0x32, 0x78, 0x63, 0x62, 0x6b, 0x30, 0x7c,
121            0x8d, 0xc8, 0x15, 0x22, 0x90, 0x91,
122        ],
123    };
124
125    assert_eq!(expected, message);
126}