Skip to main content

rustbac_core/services/
device_management.rs

1use crate::apdu::ConfirmedRequestHeader;
2use crate::encoding::{
3    primitives::{encode_ctx_character_string, encode_ctx_unsigned},
4    writer::Writer,
5};
6use crate::EncodeError;
7
8pub const SERVICE_DEVICE_COMMUNICATION_CONTROL: u8 = 0x11;
9pub const SERVICE_REINITIALIZE_DEVICE: u8 = 0x14;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12#[repr(u32)]
13pub enum DeviceCommunicationState {
14    Enable = 0,
15    Disable = 1,
16    DisableInitiation = 2,
17}
18
19impl DeviceCommunicationState {
20    pub const fn to_u32(self) -> u32 {
21        self as u32
22    }
23}
24
25#[derive(Debug, Clone, Copy, PartialEq, Eq)]
26#[repr(u32)]
27pub enum ReinitializeState {
28    Coldstart = 0,
29    Warmstart = 1,
30    StartBackup = 2,
31    EndBackup = 3,
32    StartRestore = 4,
33    EndRestore = 5,
34    AbortRestore = 6,
35    ActivateChanges = 7,
36}
37
38impl ReinitializeState {
39    pub const fn to_u32(self) -> u32 {
40        self as u32
41    }
42}
43
44#[derive(Debug, Clone, Copy, PartialEq, Eq)]
45pub struct DeviceCommunicationControlRequest<'a> {
46    pub time_duration_seconds: Option<u16>,
47    pub enable_disable: DeviceCommunicationState,
48    pub password: Option<&'a str>,
49    pub invoke_id: u8,
50}
51
52impl<'a> DeviceCommunicationControlRequest<'a> {
53    pub fn encode(&self, w: &mut Writer<'_>) -> Result<(), EncodeError> {
54        ConfirmedRequestHeader {
55            segmented: false,
56            more_follows: false,
57            segmented_response_accepted: false,
58            max_segments: 0,
59            max_apdu: 5,
60            invoke_id: self.invoke_id,
61            sequence_number: None,
62            proposed_window_size: None,
63            service_choice: SERVICE_DEVICE_COMMUNICATION_CONTROL,
64        }
65        .encode(w)?;
66        if let Some(duration) = self.time_duration_seconds {
67            encode_ctx_unsigned(w, 0, duration as u32)?;
68        }
69        encode_ctx_unsigned(w, 1, self.enable_disable.to_u32())?;
70        if let Some(password) = self.password {
71            encode_ctx_character_string(w, 2, password)?;
72        }
73        Ok(())
74    }
75}
76
77#[derive(Debug, Clone, Copy, PartialEq, Eq)]
78pub struct ReinitializeDeviceRequest<'a> {
79    pub state: ReinitializeState,
80    pub password: Option<&'a str>,
81    pub invoke_id: u8,
82}
83
84impl<'a> ReinitializeDeviceRequest<'a> {
85    pub fn encode(&self, w: &mut Writer<'_>) -> Result<(), EncodeError> {
86        ConfirmedRequestHeader {
87            segmented: false,
88            more_follows: false,
89            segmented_response_accepted: false,
90            max_segments: 0,
91            max_apdu: 5,
92            invoke_id: self.invoke_id,
93            sequence_number: None,
94            proposed_window_size: None,
95            service_choice: SERVICE_REINITIALIZE_DEVICE,
96        }
97        .encode(w)?;
98        encode_ctx_unsigned(w, 0, self.state.to_u32())?;
99        if let Some(password) = self.password {
100            encode_ctx_character_string(w, 1, password)?;
101        }
102        Ok(())
103    }
104}
105
106#[cfg(test)]
107mod tests {
108    use super::{
109        DeviceCommunicationControlRequest, DeviceCommunicationState, ReinitializeDeviceRequest,
110        ReinitializeState, SERVICE_DEVICE_COMMUNICATION_CONTROL, SERVICE_REINITIALIZE_DEVICE,
111    };
112    use crate::apdu::ConfirmedRequestHeader;
113    use crate::encoding::{reader::Reader, writer::Writer};
114
115    #[test]
116    fn encode_device_communication_control_request() {
117        let req = DeviceCommunicationControlRequest {
118            time_duration_seconds: Some(120),
119            enable_disable: DeviceCommunicationState::Disable,
120            password: Some("secret"),
121            invoke_id: 7,
122        };
123        let mut buf = [0u8; 96];
124        let mut w = Writer::new(&mut buf);
125        req.encode(&mut w).unwrap();
126
127        let mut r = Reader::new(w.as_written());
128        let hdr = ConfirmedRequestHeader::decode(&mut r).unwrap();
129        assert_eq!(hdr.service_choice, SERVICE_DEVICE_COMMUNICATION_CONTROL);
130        assert_eq!(hdr.invoke_id, 7);
131    }
132
133    #[test]
134    fn encode_reinitialize_device_request() {
135        let req = ReinitializeDeviceRequest {
136            state: ReinitializeState::ActivateChanges,
137            password: None,
138            invoke_id: 11,
139        };
140        let mut buf = [0u8; 64];
141        let mut w = Writer::new(&mut buf);
142        req.encode(&mut w).unwrap();
143
144        let mut r = Reader::new(w.as_written());
145        let hdr = ConfirmedRequestHeader::decode(&mut r).unwrap();
146        assert_eq!(hdr.service_choice, SERVICE_REINITIALIZE_DEVICE);
147        assert_eq!(hdr.invoke_id, 11);
148    }
149}