at_cryptoauth/
packet.rs

1use super::command::OpCode;
2use super::error::{Error, ErrorKind, Status};
3use crate::datalink::Transaction;
4use core::convert::{TryFrom, TryInto};
5use core::mem::size_of;
6use core::ops::RangeTo;
7use crc::{Algorithm, Crc};
8
9// Offset by word_address (1 byte)
10const PACKET_OFFSET: usize = 1;
11// PACKET_OFFSET + length (1 byte), opcode (1 byte), p1 (1 byte), p2 (2 bytes)
12const PDU_OFFSET: usize = 6;
13// Length (1 byte), opcode (1 byte), p1 (1 byte), p2 (2 bytes), crc (2 bytes)
14const CMD_SIZE_MIN: usize = 7;
15
16// Parameters to calculate CRC.
17const CUSTOM_ALG: Algorithm<u16> = Algorithm {
18    poly: 0x8005,
19    init: 0x0000,
20    refin: true,
21    refout: false,
22    xorout: 0x0000,
23    check: 0xbcdd,
24    residue: 0x0000,
25};
26
27// CRC memoise table
28pub const CRC16: Crc<u16> = Crc::<u16>::new(&CUSTOM_ALG);
29
30#[derive(Debug)]
31pub(crate) struct PacketBuilder<'a> {
32    buffer: &'a mut [u8],
33    pdu_length: Option<usize>,
34    opcode: Option<OpCode>,
35    mode: Option<u8>,
36    param2: Option<u16>,
37}
38
39impl<'a> PacketBuilder<'a> {
40    pub(crate) fn new(buffer: &'a mut [u8]) -> Self {
41        Self {
42            buffer,
43            pdu_length: None,
44            opcode: None,
45            mode: None,
46            param2: None,
47        }
48    }
49
50    pub(crate) fn opcode(&mut self, opcode: OpCode) -> &mut Self {
51        self.opcode.replace(opcode);
52        self
53    }
54
55    /// Mode parameter also referred as `param1`.
56    pub(crate) fn mode(&mut self, mode: u8) -> &mut Self {
57        self.mode.replace(mode);
58        self
59    }
60
61    /// Key ID
62    pub(crate) fn param2(&mut self, param2: u16) -> &mut Self {
63        self.param2.replace(param2);
64        self
65    }
66
67    pub(crate) fn pdu_data(&mut self, data: impl AsRef<[u8]>) -> &mut Self {
68        let data_length = data.as_ref().len();
69        self.buffer[PDU_OFFSET..PDU_OFFSET + data_length]
70            .as_mut()
71            .copy_from_slice(data.as_ref());
72        self.pdu_length.replace(data_length);
73        self
74    }
75
76    // Input length cannot exceed the length of underlying buffer. Only use it
77    // for packets of fixed length. Also note that `pdu_data` modifies `pdu_length`.
78    pub(crate) fn pdu_length(&mut self, length: usize) -> &mut Self {
79        self.pdu_length.replace(length);
80        self
81    }
82
83    pub(crate) fn packet_buffer(&mut self) -> &mut [u8] {
84        self.buffer[PACKET_OFFSET..].as_mut()
85    }
86
87    pub(crate) fn pdu_buffer(&mut self) -> &mut [u8] {
88        self.buffer[PDU_OFFSET..].as_mut()
89    }
90
91    pub(crate) fn build(&mut self) -> Result<Packet, Error> {
92        let packet_length = self
93            .pdu_length
94            .iter()
95            .fold(CMD_SIZE_MIN, |min, pdu_len| min + pdu_len);
96        let opcode = self.opcode.ok_or(Error::from(ErrorKind::BadOpcode))?;
97        let mode = self.mode.unwrap_or_default();
98        let param2 = self.param2.unwrap_or_default();
99
100        // Packet encoder is Hand-crafted. Any helpful library?
101        self.buffer[0] = Transaction::Command as u8;
102        let packet = self.packet_buffer();
103        packet[0] = packet_length as u8;
104        packet[1] = opcode as u8;
105        packet[2] = mode;
106        packet[3..5]
107            .as_mut()
108            .copy_from_slice(param2.to_le_bytes().as_ref());
109
110        let crc_offset = packet_length - size_of::<u16>();
111        let crc = CRC16.checksum(&packet[..crc_offset]);
112        packet[crc_offset..packet_length]
113            .as_mut()
114            .copy_from_slice(crc.to_le_bytes().as_ref());
115        Ok(Packet {
116            opcode,
117            range: (..packet_length + PACKET_OFFSET),
118        })
119    }
120}
121
122impl<'a> From<&'a mut [u8]> for PacketBuilder<'a> {
123    fn from(buffer: &'a mut [u8]) -> Self {
124        Self::new(buffer)
125    }
126}
127
128/// Assuming buffer is alocated elsewhere, `Packet` designates subslice in use.
129#[derive(Clone, Copy, Debug)]
130pub(crate) struct Packet {
131    opcode: OpCode,
132    range: RangeTo<usize>,
133}
134
135impl Packet {
136    pub(crate) fn opcode(&self) -> &OpCode {
137        &self.opcode
138    }
139
140    pub(crate) fn buffer(self, buffer: &[u8]) -> &[u8] {
141        buffer[self.range].as_ref()
142    }
143}
144
145// Is it possible to classify the response into [] | [u8; WORD] | [u8; BLOCK]?
146// TODO: Testing purpose only. Should not be public.
147#[derive(Clone, Copy, Debug)]
148pub struct Response<'a> {
149    pdu: &'a [u8],
150}
151
152impl<'a> Response<'a> {
153    /// Check if the response indicates an error. The received data is expected
154    /// to be in the form of a CA device response frame.
155    /// Extract PDU.
156    pub(crate) fn new(buffer: &'a [u8]) -> Result<Self, Error> {
157        // Check if buffer is well-formed.
158        if buffer.len() < 0x04 {
159            // Buffer is too small. Bail out.
160            return Err(ErrorKind::RxFail.into());
161        }
162
163        // Check CRC.
164        let (payload, crc_bytes) = buffer.split_at(buffer.len() - size_of::<u16>());
165        let crc = crc_bytes
166            .try_into()
167            .map(u16::from_le_bytes)
168            .unwrap_or_else(|_| unreachable!());
169        if crc != CRC16.checksum(&payload) {
170            return Err(ErrorKind::RxCrcError.into());
171        }
172
173        // Check error status. Error packets are always 4 bytes long.
174        let (header, pdu) = payload.split_at(1);
175        if header[0] == 0x04 {
176            if let Ok(status) = Status::try_from(pdu[0]) {
177                return Err(status.into());
178            }
179        }
180
181        Ok(Self { pdu })
182    }
183}
184
185impl<'a> AsRef<[u8]> for Response<'a> {
186    fn as_ref(&self) -> &[u8] {
187        self.pdu
188    }
189}