dot15d4_frame/
frame_control.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
//! IEEE 802.15.4 Frame Control field readers and writers.

use super::AddressingMode;
use super::{Error, Result};

/// IEEE 802.15.4 frame type.
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
pub enum FrameType {
    /// Beacon frame.
    Beacon = 0b000,
    /// Data frame.
    Data = 0b001,
    /// Acknowledgement frame.
    Ack = 0b010,
    /// MAC command frame.
    MacCommand = 0b011,
    /// Multipurpose frame.
    Multipurpose = 0b101,
    /// Fragmentation frame.
    FragmentOrFrak = 0b110,
    /// Extended frame.
    Extended = 0b111,
    /// Unknown frame type.
    Unknown,
}

impl From<u8> for FrameType {
    fn from(value: u8) -> Self {
        match value {
            0b000 => Self::Beacon,
            0b001 => Self::Data,
            0b010 => Self::Ack,
            0b011 => Self::MacCommand,
            0b101 => Self::Multipurpose,
            0b110 => Self::FragmentOrFrak,
            0b111 => Self::Extended,
            _ => Self::Unknown,
        }
    }
}

/// IEEE 802.15.4 frame version.
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
pub enum FrameVersion {
    /// IEEE 802.15.4-2003 frame version.
    Ieee802154_2003 = 0b00,
    /// IEEE 802.15.4-2006 frame version.
    Ieee802154_2006 = 0b01,
    /// IEEE 802.15.4-2020 frame version.
    Ieee802154_2020 = 0b10,
    /// Unknown frame version.
    Unknown,
}

impl From<u8> for FrameVersion {
    fn from(value: u8) -> Self {
        match value {
            0b00 => Self::Ieee802154_2003,
            0b01 => Self::Ieee802154_2006,
            0b10 => Self::Ieee802154_2020,
            _ => Self::Unknown,
        }
    }
}

/// A reader/writer for the IEEE 802.15.4 Frame Control field.
pub struct FrameControl<T: AsRef<[u8]>> {
    buffer: T,
}

impl<T: AsRef<[u8]>> FrameControl<T> {
    /// Create a new [`FrameControl`] reader/writer from a given buffer.
    ///
    /// # Errors
    ///
    /// Returns an error if the buffer is too short.
    pub fn new(buffer: T) -> Result<Self> {
        let fc = Self::new_unchecked(buffer);

        if !fc.check_len() {
            return Err(Error);
        }

        Ok(fc)
    }

    /// Returns `false` if the buffer is too short to contain the Frame Control
    /// field.
    fn check_len(&self) -> bool {
        self.buffer.as_ref().len() >= 2
    }

    /// Create a new [`FrameControl`] reader/writer from a given buffer without
    /// length checking.
    pub fn new_unchecked(buffer: T) -> Self {
        Self { buffer }
    }

    /// Return the inner buffer.
    pub fn into_inner(self) -> T {
        self.buffer
    }

    /// Return the [`FrameType`] field.
    pub fn frame_type(&self) -> FrameType {
        let b = &self.buffer.as_ref()[..2];
        FrameType::from((u16::from_le_bytes([b[0], b[1]]) & 0b111) as u8)
    }

    /// Returns `true` when the security enabled field is set.
    pub fn security_enabled(&self) -> bool {
        let b = &self.buffer.as_ref()[..2];
        ((u16::from_le_bytes([b[0], b[1]]) >> 3) & 0b1) == 1
    }

    /// Returns `true` when the frame pending field is set.
    pub fn frame_pending(&self) -> bool {
        let b = &self.buffer.as_ref()[..2];
        ((u16::from_le_bytes([b[0], b[1]]) >> 4) & 0b1) == 1
    }

    /// Returns `true` when the acknowledgement request field is set.
    pub fn ack_request(&self) -> bool {
        let b = &self.buffer.as_ref()[..2];
        ((u16::from_le_bytes([b[0], b[1]]) >> 5) & 0b1) == 1
    }

    /// Returns `true` when the PAN ID compression field is set.
    pub fn pan_id_compression(&self) -> bool {
        let b = &self.buffer.as_ref()[..2];
        ((u16::from_le_bytes([b[0], b[1]]) >> 6) & 0b1) == 1
    }

    /// Returns `true` when the sequence number suppression field is set.
    pub fn sequence_number_suppression(&self) -> bool {
        let b = &self.buffer.as_ref()[..2];
        ((u16::from_le_bytes([b[0], b[1]]) >> 8) & 0b1) == 1
    }

    /// Returns `true` when the information element field is set.
    pub fn information_elements_present(&self) -> bool {
        let b = &self.buffer.as_ref()[..2];
        ((u16::from_le_bytes([b[0], b[1]]) >> 9) & 0b1) == 1
    }

    /// Return the Destination [`AddressingMode`].
    pub fn dst_addressing_mode(&self) -> AddressingMode {
        let b = &self.buffer.as_ref()[..2];
        let raw = (u16::from_le_bytes([b[0], b[1]]) >> 10) & 0b11;
        AddressingMode::from(raw as u8)
    }

    /// Return the Source [`AddressingMode`].
    pub fn src_addressing_mode(&self) -> AddressingMode {
        let b = &self.buffer.as_ref()[..2];
        let raw = (u16::from_le_bytes([b[0], b[1]]) >> 14) & 0b11;
        AddressingMode::from(raw as u8)
    }

    /// Return the [`FrameVersion`].
    pub fn frame_version(&self) -> FrameVersion {
        let b = &self.buffer.as_ref()[..2];
        let raw = (u16::from_le_bytes([b[0], b[1]]) >> 12) & 0b11;
        FrameVersion::from(raw as u8)
    }
}

impl<T: AsRef<[u8]> + AsMut<[u8]>> FrameControl<T> {
    /// Set the frame type field.
    pub fn set_frame_type(&mut self, frame_type: FrameType) {
        let b = &mut self.buffer.as_mut()[..2];
        let mut raw = u16::from_le_bytes([b[0], b[1]]);
        raw = (raw & !0b111) | ((frame_type as u8) as u16 & 0b111);
        b.copy_from_slice(&raw.to_le_bytes());
    }

    /// Set the security enabled field.
    pub fn set_security_enabled(&mut self, security_enabled: bool) {
        let b = &mut self.buffer.as_mut()[..2];
        let mut raw = u16::from_le_bytes([b[0], b[1]]);
        raw |= (security_enabled as u16) << 3;
        b.copy_from_slice(&raw.to_le_bytes());
    }

    /// Set the frame pending field.
    pub fn set_frame_pending(&mut self, frame_pending: bool) {
        let b = &mut self.buffer.as_mut()[..2];
        let mut raw = u16::from_le_bytes([b[0], b[1]]);
        raw |= (frame_pending as u16) << 4;
        b.copy_from_slice(&raw.to_le_bytes());
    }

    /// Set the acknowledgement request field.
    pub fn set_ack_request(&mut self, ack_request: bool) {
        let b = &mut self.buffer.as_mut()[..2];
        let mut raw = u16::from_le_bytes([b[0], b[1]]);
        raw |= (ack_request as u16) << 5;
        b.copy_from_slice(&raw.to_le_bytes());
    }

    /// Set the PAN ID compression field.
    pub fn set_pan_id_compression(&mut self, pan_id_compression: bool) {
        let b = &mut self.buffer.as_mut()[..2];
        let mut raw = u16::from_le_bytes([b[0], b[1]]);
        raw |= (pan_id_compression as u16) << 6;
        b.copy_from_slice(&raw.to_le_bytes());
    }

    /// Set the sequence number suppression field.
    pub fn set_sequence_number_suppression(&mut self, sequence_number_suppression: bool) {
        let b = &mut self.buffer.as_mut()[..2];
        let mut raw = u16::from_le_bytes([b[0], b[1]]);
        raw |= (sequence_number_suppression as u16) << 8;
        b.copy_from_slice(&raw.to_le_bytes());
    }

    /// Set the information element present field.
    pub fn set_information_elements_present(&mut self, information_elements_present: bool) {
        let b = &mut self.buffer.as_mut()[..2];
        let mut raw = u16::from_le_bytes([b[0], b[1]]);
        raw |= (information_elements_present as u16) << 9;
        b.copy_from_slice(&raw.to_le_bytes());
    }

    /// Set the destination addressing mode field.
    pub fn set_dst_addressing_mode(&mut self, addressing_mode: AddressingMode) {
        let b = &mut self.buffer.as_mut()[..2];
        let mut raw = u16::from_le_bytes([b[0], b[1]]);
        raw = (raw & !(0b11 << 10)) | (((addressing_mode as u8) as u16 & 0b11) << 10);
        b.copy_from_slice(&raw.to_le_bytes());
    }

    /// Set the source addressing mode field.
    pub fn set_src_addressing_mode(&mut self, addressing_mode: AddressingMode) {
        let b = &mut self.buffer.as_mut()[..2];
        let mut raw = u16::from_le_bytes([b[0], b[1]]);
        raw = (raw & !(0b11 << 14)) | (((addressing_mode as u8) as u16 & 0b11) << 14);
        b.copy_from_slice(&raw.to_le_bytes());
    }

    /// Set the frame version field.
    pub fn set_frame_version(&mut self, frame_version: FrameVersion) {
        let b = &mut self.buffer.as_mut()[..2];
        let mut raw = u16::from_le_bytes([b[0], b[1]]);
        raw = (raw & !(0b11 << 12)) | (((frame_version as u8) as u16 & 0b11) << 12);
        b.copy_from_slice(&raw.to_le_bytes());
    }
}

impl<T: AsRef<[u8]>> core::fmt::Display for FrameControl<T> {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        writeln!(f, "Frame Control")?;
        writeln!(f, "  type: {:?}", self.frame_type())?;
        writeln!(
            f,
            "  security enabled: {}",
            self.security_enabled() as usize
        )?;
        writeln!(f, "  frame pending: {}", self.frame_pending() as usize)?;
        writeln!(f, "  ack request: {}", self.ack_request() as usize)?;
        writeln!(
            f,
            "  pan id compression: {}",
            self.pan_id_compression() as usize
        )?;
        writeln!(
            f,
            "  sequence number suppression: {}",
            self.sequence_number_suppression() as usize
        )?;
        writeln!(
            f,
            "  information elements present: {}",
            self.information_elements_present() as usize
        )?;
        writeln!(f, "  dst addressing mode: {:?}", self.dst_addressing_mode())?;
        writeln!(f, "  src addressing mode: {:?}", self.src_addressing_mode())?;
        writeln!(f, "  frame version: {:?}", self.frame_version())?;
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn bad_length() {
        let fc = [0x0];
        assert!(FrameControl::new(&fc).is_err());
    }

    #[test]
    fn get_fields() {
        let fc = [0x0, 0x0];
        let fc = FrameControl::new(&fc).unwrap();
        assert_eq!(fc.frame_type(), FrameType::Beacon);
        assert!(!fc.security_enabled());
        assert!(!fc.frame_pending());
        assert!(!fc.ack_request());
        assert!(!fc.pan_id_compression());
        assert!(!fc.sequence_number_suppression());
        assert!(!fc.information_elements_present());
        assert_eq!(fc.dst_addressing_mode(), AddressingMode::Absent);
        assert_eq!(fc.src_addressing_mode(), AddressingMode::Absent);
        assert_eq!(fc.frame_version(), FrameVersion::Ieee802154_2003);

        let fc = [0b0010_1001, 0b1010_1010];
        let fc = FrameControl::new(&fc).unwrap();
        assert_eq!(fc.frame_type(), FrameType::Data);
        assert!(fc.security_enabled());
        assert!(!fc.frame_pending());
        assert!(fc.ack_request());
        assert!(!fc.pan_id_compression());
        assert!(!fc.sequence_number_suppression());
        assert!(fc.information_elements_present());
        assert_eq!(fc.dst_addressing_mode(), AddressingMode::Short);
        assert_eq!(fc.src_addressing_mode(), AddressingMode::Short);
        assert_eq!(fc.frame_version(), FrameVersion::Ieee802154_2020);
    }

    #[test]
    fn set_fields() {
        let mut fc = [0x0, 0x0];
        let mut fc = FrameControl::new_unchecked(&mut fc);
        fc.set_frame_type(FrameType::Beacon);
        fc.set_security_enabled(false);
        fc.set_frame_pending(false);
        fc.set_ack_request(false);
        fc.set_pan_id_compression(false);
        fc.set_sequence_number_suppression(false);
        fc.set_information_elements_present(false);
        fc.set_dst_addressing_mode(AddressingMode::Absent);
        fc.set_src_addressing_mode(AddressingMode::Absent);
        fc.set_frame_version(FrameVersion::Ieee802154_2003);
        assert_eq!(*fc.into_inner(), [0x0, 0x0]);

        let mut fc = [0x0, 0x0];
        let mut fc = FrameControl::new_unchecked(&mut fc);
        fc.set_frame_type(FrameType::Data);
        fc.set_security_enabled(true);
        fc.set_frame_pending(false);
        fc.set_ack_request(true);
        fc.set_pan_id_compression(false);
        fc.set_sequence_number_suppression(false);
        fc.set_information_elements_present(true);
        fc.set_dst_addressing_mode(AddressingMode::Short);
        fc.set_src_addressing_mode(AddressingMode::Short);
        fc.set_frame_version(FrameVersion::Ieee802154_2020);
        assert_eq!(*fc.into_inner(), [0b0010_1001, 0b1010_1010]);
    }

    #[test]
    fn frame_type() {
        assert_eq!(FrameType::from(0b000), FrameType::Beacon);
        assert_eq!(FrameType::from(0b001), FrameType::Data);
        assert_eq!(FrameType::from(0b010), FrameType::Ack);
        assert_eq!(FrameType::from(0b011), FrameType::MacCommand);
        assert_eq!(FrameType::from(0b101), FrameType::Multipurpose);
        assert_eq!(FrameType::from(0b110), FrameType::FragmentOrFrak);
        assert_eq!(FrameType::from(0b111), FrameType::Extended);
        assert_eq!(FrameType::from(0b100), FrameType::Unknown);
    }

    #[test]
    fn frame_version() {
        assert_eq!(FrameVersion::from(0b00), FrameVersion::Ieee802154_2003);
        assert_eq!(FrameVersion::from(0b01), FrameVersion::Ieee802154_2006);
        assert_eq!(FrameVersion::from(0b10), FrameVersion::Ieee802154_2020);
        assert_eq!(FrameVersion::from(0b11), FrameVersion::Unknown);
    }

    #[test]
    fn formatting() {
        let fc = [0b0010_1001, 0b1010_1010];
        let fc = FrameControl::new(&fc).unwrap();
        assert_eq!(
            format!("{}", fc),
            r"Frame Control
  type: Data
  security enabled: 1
  frame pending: 0
  ack request: 1
  pan id compression: 0
  sequence number suppression: 0
  information elements present: 1
  dst addressing mode: Short
  src addressing mode: Short
  frame version: Ieee802154_2020
"
        );
    }
}