Skip to main content

smoltcp/wire/
ieee802154.rs

1use core::fmt;
2
3use byteorder::{ByteOrder, LittleEndian};
4
5use super::{Error, Result};
6use crate::wire::Ipv6Address;
7
8enum_with_unknown! {
9    /// IEEE 802.15.4 frame type.
10    pub enum FrameType(u8) {
11        Beacon = 0b000,
12        Data = 0b001,
13        Acknowledgement = 0b010,
14        MacCommand = 0b011,
15        Multipurpose = 0b101,
16        FragmentOrFrak = 0b110,
17        Extended = 0b111,
18    }
19}
20
21impl fmt::Display for FrameType {
22    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
23        match self {
24            FrameType::Beacon => write!(f, "Beacon"),
25            FrameType::Data => write!(f, "Data"),
26            FrameType::Acknowledgement => write!(f, "Ack"),
27            FrameType::MacCommand => write!(f, "MAC command"),
28            FrameType::Multipurpose => write!(f, "Multipurpose"),
29            FrameType::FragmentOrFrak => write!(f, "FragmentOrFrak"),
30            FrameType::Extended => write!(f, "Extended"),
31            FrameType::Unknown(id) => write!(f, "0b{id:04b}"),
32        }
33    }
34}
35enum_with_unknown! {
36    /// IEEE 802.15.4 addressing mode for destination and source addresses.
37    pub enum AddressingMode(u8) {
38        Absent    = 0b00,
39        Short     = 0b10,
40        Extended  = 0b11,
41    }
42}
43
44impl AddressingMode {
45    /// Return the size in octets of the address.
46    const fn size(&self) -> usize {
47        match self {
48            AddressingMode::Absent => 0,
49            AddressingMode::Short => 2,
50            AddressingMode::Extended => 8,
51            AddressingMode::Unknown(_) => 0, // TODO(thvdveld): what do we need to here?
52        }
53    }
54}
55
56impl fmt::Display for AddressingMode {
57    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
58        match self {
59            AddressingMode::Absent => write!(f, "Absent"),
60            AddressingMode::Short => write!(f, "Short"),
61            AddressingMode::Extended => write!(f, "Extended"),
62            AddressingMode::Unknown(id) => write!(f, "0b{id:04b}"),
63        }
64    }
65}
66
67/// A IEEE 802.15.4 PAN.
68#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
69pub struct Pan(pub u16);
70
71impl Pan {
72    pub const BROADCAST: Self = Self(0xffff);
73
74    /// Return the PAN ID as bytes.
75    pub fn as_bytes(&self) -> [u8; 2] {
76        let mut pan = [0u8; 2];
77        LittleEndian::write_u16(&mut pan, self.0);
78        pan
79    }
80}
81
82impl fmt::Display for Pan {
83    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
84        write!(f, "{:0x}", self.0)
85    }
86}
87
88#[cfg(feature = "defmt")]
89impl defmt::Format for Pan {
90    fn format(&self, fmt: defmt::Formatter) {
91        defmt::write!(fmt, "{:02x}", self.0)
92    }
93}
94
95/// A IEEE 802.15.4 address.
96#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
97pub enum Address {
98    Absent,
99    Short([u8; 2]),
100    Extended([u8; 8]),
101}
102
103#[cfg(feature = "defmt")]
104impl defmt::Format for Address {
105    fn format(&self, f: defmt::Formatter) {
106        match self {
107            Self::Absent => defmt::write!(f, "not-present"),
108            Self::Short(bytes) => defmt::write!(f, "{:02x}:{:02x}", bytes[0], bytes[1]),
109            Self::Extended(bytes) => defmt::write!(
110                f,
111                "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
112                bytes[0],
113                bytes[1],
114                bytes[2],
115                bytes[3],
116                bytes[4],
117                bytes[5],
118                bytes[6],
119                bytes[7]
120            ),
121        }
122    }
123}
124
125#[cfg(test)]
126impl Default for Address {
127    fn default() -> Self {
128        Address::Extended([0u8; 8])
129    }
130}
131
132impl Address {
133    /// The broadcast address.
134    pub const BROADCAST: Address = Address::Short([0xff; 2]);
135
136    /// Query whether the address is an unicast address.
137    pub fn is_unicast(&self) -> bool {
138        !self.is_broadcast()
139    }
140
141    /// Query whether this address is the broadcast address.
142    pub fn is_broadcast(&self) -> bool {
143        *self == Self::BROADCAST
144    }
145
146    const fn short_from_bytes(a: [u8; 2]) -> Self {
147        Self::Short(a)
148    }
149
150    const fn extended_from_bytes(a: [u8; 8]) -> Self {
151        Self::Extended(a)
152    }
153
154    pub fn from_bytes(a: &[u8]) -> Self {
155        if a.len() == 2 {
156            let mut b = [0u8; 2];
157            b.copy_from_slice(a);
158            Address::Short(b)
159        } else if a.len() == 8 {
160            let mut b = [0u8; 8];
161            b.copy_from_slice(a);
162            Address::Extended(b)
163        } else {
164            panic!("Not an IEEE802.15.4 address");
165        }
166    }
167
168    pub const fn as_bytes(&self) -> &[u8] {
169        match self {
170            Address::Absent => &[],
171            Address::Short(value) => value,
172            Address::Extended(value) => value,
173        }
174    }
175
176    /// Convert the extended address to an Extended Unique Identifier (EUI-64)
177    pub fn as_eui_64(&self) -> Option<[u8; 8]> {
178        match self {
179            Address::Absent | Address::Short(_) => None,
180            Address::Extended(value) => {
181                let mut bytes = [0; 8];
182                bytes.copy_from_slice(&value[..]);
183
184                bytes[0] ^= 1 << 1;
185
186                Some(bytes)
187            }
188        }
189    }
190
191    /// Convert an extended address to a link-local IPv6 address using the EUI-64 format from
192    /// RFC2464.
193    pub fn as_link_local_address(&self) -> Option<Ipv6Address> {
194        let mut bytes = [0; 16];
195        bytes[0] = 0xfe;
196        bytes[1] = 0x80;
197        bytes[8..].copy_from_slice(&self.as_eui_64()?);
198
199        Some(Ipv6Address::from_octets(bytes))
200    }
201}
202
203impl fmt::Display for Address {
204    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
205        match self {
206            Self::Absent => write!(f, "not-present"),
207            Self::Short(bytes) => write!(f, "{:02x}:{:02x}", bytes[0], bytes[1]),
208            Self::Extended(bytes) => write!(
209                f,
210                "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
211                bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7]
212            ),
213        }
214    }
215}
216
217enum_with_unknown! {
218    /// IEEE 802.15.4 addressing mode for destination and source addresses.
219    pub enum FrameVersion(u8) {
220        Ieee802154_2003 = 0b00,
221        Ieee802154_2006 = 0b01,
222        Ieee802154 = 0b10,
223    }
224}
225
226/// A read/write wrapper around an IEEE 802.15.4 frame buffer.
227#[derive(Debug, Clone)]
228pub struct Frame<T: AsRef<[u8]>> {
229    buffer: T,
230}
231
232mod field {
233    use crate::wire::field::*;
234
235    pub const FRAMECONTROL: Field = 0..2;
236    pub const SEQUENCE_NUMBER: usize = 2;
237    pub const ADDRESSING: Rest = 3..;
238}
239
240macro_rules! fc_bit_field {
241    ($field:ident, $bit:literal) => {
242        #[inline]
243        pub fn $field(&self) -> bool {
244            let data = self.buffer.as_ref();
245            let raw = LittleEndian::read_u16(&data[field::FRAMECONTROL]);
246
247            ((raw >> $bit) & 0b1) == 0b1
248        }
249    };
250}
251
252macro_rules! set_fc_bit_field {
253    ($field:ident, $bit:literal) => {
254        #[inline]
255        pub fn $field(&mut self, val: bool) {
256            let data = &mut self.buffer.as_mut()[field::FRAMECONTROL];
257            let mut raw = LittleEndian::read_u16(data);
258            raw |= ((val as u16) << $bit);
259
260            data.copy_from_slice(&raw.to_le_bytes());
261        }
262    };
263}
264
265impl<T: AsRef<[u8]>> Frame<T> {
266    /// Input a raw octet buffer with Ethernet frame structure.
267    pub const fn new_unchecked(buffer: T) -> Frame<T> {
268        Frame { buffer }
269    }
270
271    /// Shorthand for a combination of [new_unchecked] and [check_len].
272    ///
273    /// [new_unchecked]: #method.new_unchecked
274    /// [check_len]: #method.check_len
275    pub fn new_checked(buffer: T) -> Result<Frame<T>> {
276        let packet = Self::new_unchecked(buffer);
277        packet.check_len()?;
278
279        // We don't handle unknown frame versions.
280        if matches!(packet.frame_version(), FrameVersion::Unknown(_)) {
281            return Err(Error);
282        }
283
284        // We don't handle unknown addressing modes.
285        if matches!(packet.dst_addressing_mode(), AddressingMode::Unknown(_))
286            || matches!(packet.src_addressing_mode(), AddressingMode::Unknown(_))
287        {
288            return Err(Error);
289        }
290
291        // We don't handle absent addressing mode with PAN ID compression for older frame versions.
292        if matches!(
293            packet.frame_version(),
294            FrameVersion::Ieee802154_2003 | FrameVersion::Ieee802154_2006
295        ) && packet.pan_id_compression()
296            && matches!(packet.dst_addressing_mode(), AddressingMode::Absent)
297            && matches!(packet.src_addressing_mode(), AddressingMode::Absent)
298        {
299            return Err(Error);
300        }
301
302        Ok(packet)
303    }
304
305    /// Ensure that no accessor method will panic if called.
306    /// Returns `Err(Error)` if the buffer is too short.
307    pub fn check_len(&self) -> Result<()> {
308        // We need at least 3 bytes
309        if self.buffer.as_ref().len() < 3 {
310            return Err(Error);
311        }
312
313        // We don't handle frames with a payload larger than 127 bytes.
314        if self.buffer.as_ref().len() > 127 {
315            return Err(Error);
316        }
317
318        let mut offset = field::ADDRESSING.start
319            + if let Some((dst_pan_id, dst_addr, src_pan_id, src_addr)) = self.addr_present_flags()
320            {
321                let mut offset = if dst_pan_id { 2 } else { 0 };
322                offset += dst_addr.size();
323                offset += if src_pan_id { 2 } else { 0 };
324                offset += src_addr.size();
325
326                if offset > self.buffer.as_ref().len() {
327                    return Err(Error);
328                }
329                offset
330            } else {
331                0
332            };
333
334        if self.security_enabled() {
335            // First check that we can access the security header control bits.
336            if offset + 1 > self.buffer.as_ref().len() {
337                return Err(Error);
338            }
339
340            offset += self.security_header_len();
341        }
342
343        if offset > self.buffer.as_ref().len() {
344            return Err(Error);
345        }
346
347        Ok(())
348    }
349
350    /// Consumes the frame, returning the underlying buffer.
351    pub fn into_inner(self) -> T {
352        self.buffer
353    }
354
355    /// Return the FrameType field.
356    #[inline]
357    pub fn frame_type(&self) -> FrameType {
358        let data = self.buffer.as_ref();
359        let raw = LittleEndian::read_u16(&data[field::FRAMECONTROL]);
360        let ft = (raw & 0b111) as u8;
361        FrameType::from(ft)
362    }
363
364    fc_bit_field!(security_enabled, 3);
365    fc_bit_field!(frame_pending, 4);
366    fc_bit_field!(ack_request, 5);
367    fc_bit_field!(pan_id_compression, 6);
368
369    fc_bit_field!(sequence_number_suppression, 8);
370    fc_bit_field!(ie_present, 9);
371
372    /// Return the destination addressing mode.
373    #[inline]
374    pub fn dst_addressing_mode(&self) -> AddressingMode {
375        let data = self.buffer.as_ref();
376        let raw = LittleEndian::read_u16(&data[field::FRAMECONTROL]);
377        let am = ((raw >> 10) & 0b11) as u8;
378        AddressingMode::from(am)
379    }
380
381    /// Return the frame version.
382    #[inline]
383    pub fn frame_version(&self) -> FrameVersion {
384        let data = self.buffer.as_ref();
385        let raw = LittleEndian::read_u16(&data[field::FRAMECONTROL]);
386        let fv = ((raw >> 12) & 0b11) as u8;
387        FrameVersion::from(fv)
388    }
389
390    /// Return the source addressing mode.
391    #[inline]
392    pub fn src_addressing_mode(&self) -> AddressingMode {
393        let data = self.buffer.as_ref();
394        let raw = LittleEndian::read_u16(&data[field::FRAMECONTROL]);
395        let am = ((raw >> 14) & 0b11) as u8;
396        AddressingMode::from(am)
397    }
398
399    /// Return the sequence number of the frame.
400    #[inline]
401    pub fn sequence_number(&self) -> Option<u8> {
402        match self.frame_type() {
403            FrameType::Beacon
404            | FrameType::Data
405            | FrameType::Acknowledgement
406            | FrameType::MacCommand
407            | FrameType::Multipurpose => {
408                let data = self.buffer.as_ref();
409                let raw = data[field::SEQUENCE_NUMBER];
410                Some(raw)
411            }
412            FrameType::Extended | FrameType::FragmentOrFrak | FrameType::Unknown(_) => None,
413        }
414    }
415
416    /// Return the addressing fields.
417    #[inline]
418    fn addressing_fields(&self) -> Option<&[u8]> {
419        match self.frame_type() {
420            FrameType::Beacon
421            | FrameType::Data
422            | FrameType::MacCommand
423            | FrameType::Multipurpose => (),
424            FrameType::Acknowledgement if self.frame_version() == FrameVersion::Ieee802154 => (),
425            FrameType::Acknowledgement
426            | FrameType::Extended
427            | FrameType::FragmentOrFrak
428            | FrameType::Unknown(_) => return None,
429        }
430
431        if let Some((dst_pan_id, dst_addr, src_pan_id, src_addr)) = self.addr_present_flags() {
432            let mut offset = if dst_pan_id { 2 } else { 0 };
433            offset += dst_addr.size();
434            offset += if src_pan_id { 2 } else { 0 };
435            offset += src_addr.size();
436
437            let data = self.buffer.as_ref();
438            Some(&data[field::ADDRESSING][..offset])
439        } else {
440            None
441        }
442    }
443
444    fn addr_present_flags(&self) -> Option<(bool, AddressingMode, bool, AddressingMode)> {
445        let dst_addr_mode = self.dst_addressing_mode();
446        let src_addr_mode = self.src_addressing_mode();
447        let pan_id_compression = self.pan_id_compression();
448
449        use AddressingMode::*;
450        match self.frame_version() {
451            FrameVersion::Ieee802154_2003 | FrameVersion::Ieee802154_2006 => {
452                match (dst_addr_mode, src_addr_mode) {
453                    (Absent, src) => Some((false, Absent, true, src)),
454                    (dst, Absent) => Some((true, dst, false, Absent)),
455
456                    (dst, src) if pan_id_compression => Some((true, dst, false, src)),
457                    (dst, src) if !pan_id_compression => Some((true, dst, true, src)),
458                    _ => None,
459                }
460            }
461            FrameVersion::Ieee802154 => {
462                Some(match (dst_addr_mode, src_addr_mode, pan_id_compression) {
463                    (Absent, Absent, false) => (false, Absent, false, Absent),
464                    (Absent, Absent, true) => (true, Absent, false, Absent),
465                    (dst, Absent, false) if !matches!(dst, Absent) => (true, dst, false, Absent),
466                    (dst, Absent, true) if !matches!(dst, Absent) => (false, dst, false, Absent),
467                    (Absent, src, false) if !matches!(src, Absent) => (false, Absent, true, src),
468                    (Absent, src, true) if !matches!(src, Absent) => (false, Absent, true, src),
469                    (Extended, Extended, false) => (true, Extended, false, Extended),
470                    (Extended, Extended, true) => (false, Extended, false, Extended),
471                    (Short, Short, false) => (true, Short, true, Short),
472                    (Short, Extended, false) => (true, Short, true, Extended),
473                    (Extended, Short, false) => (true, Extended, true, Short),
474                    (Short, Extended, true) => (true, Short, false, Extended),
475                    (Extended, Short, true) => (true, Extended, false, Short),
476                    (Short, Short, true) => (true, Short, false, Short),
477                    _ => return None,
478                })
479            }
480            _ => None,
481        }
482    }
483
484    /// Return the destination PAN field.
485    #[inline]
486    pub fn dst_pan_id(&self) -> Option<Pan> {
487        if let Some((true, _, _, _)) = self.addr_present_flags() {
488            let addressing_fields = self.addressing_fields()?;
489            Some(Pan(LittleEndian::read_u16(&addressing_fields[..2])))
490        } else {
491            None
492        }
493    }
494
495    /// Return the destination address field.
496    #[inline]
497    pub fn dst_addr(&self) -> Option<Address> {
498        if let Some((dst_pan_id, dst_addr, _, _)) = self.addr_present_flags() {
499            let addressing_fields = self.addressing_fields()?;
500            let offset = if dst_pan_id { 2 } else { 0 };
501
502            match dst_addr {
503                AddressingMode::Absent => Some(Address::Absent),
504                AddressingMode::Short => {
505                    let mut raw = [0u8; 2];
506                    raw.clone_from_slice(&addressing_fields[offset..offset + 2]);
507                    raw.reverse();
508                    Some(Address::short_from_bytes(raw))
509                }
510                AddressingMode::Extended => {
511                    let mut raw = [0u8; 8];
512                    raw.clone_from_slice(&addressing_fields[offset..offset + 8]);
513                    raw.reverse();
514                    Some(Address::extended_from_bytes(raw))
515                }
516                AddressingMode::Unknown(_) => None,
517            }
518        } else {
519            None
520        }
521    }
522
523    /// Return the destination PAN field.
524    #[inline]
525    pub fn src_pan_id(&self) -> Option<Pan> {
526        if let Some((dst_pan_id, dst_addr, true, _)) = self.addr_present_flags() {
527            let mut offset = if dst_pan_id { 2 } else { 0 };
528            offset += dst_addr.size();
529            let addressing_fields = self.addressing_fields()?;
530            Some(Pan(LittleEndian::read_u16(
531                &addressing_fields[offset..][..2],
532            )))
533        } else {
534            None
535        }
536    }
537
538    /// Return the source address field.
539    #[inline]
540    pub fn src_addr(&self) -> Option<Address> {
541        if let Some((dst_pan_id, dst_addr, src_pan_id, src_addr)) = self.addr_present_flags() {
542            let addressing_fields = self.addressing_fields()?;
543            let mut offset = if dst_pan_id { 2 } else { 0 };
544            offset += dst_addr.size();
545            offset += if src_pan_id { 2 } else { 0 };
546
547            match src_addr {
548                AddressingMode::Absent => Some(Address::Absent),
549                AddressingMode::Short => {
550                    let mut raw = [0u8; 2];
551                    raw.clone_from_slice(&addressing_fields[offset..offset + 2]);
552                    raw.reverse();
553                    Some(Address::short_from_bytes(raw))
554                }
555                AddressingMode::Extended => {
556                    let mut raw = [0u8; 8];
557                    raw.clone_from_slice(&addressing_fields[offset..offset + 8]);
558                    raw.reverse();
559                    Some(Address::extended_from_bytes(raw))
560                }
561                AddressingMode::Unknown(_) => None,
562            }
563        } else {
564            None
565        }
566    }
567
568    /// Return the index where the auxiliary security header starts.
569    fn aux_security_header_start(&self) -> usize {
570        // We start with 3, because 2 bytes for frame control and the sequence number.
571        let mut index = 3;
572        index += if let Some(addrs) = self.addressing_fields() {
573            addrs.len()
574        } else {
575            0
576        };
577        index
578    }
579
580    /// Return the size of the security header.
581    fn security_header_len(&self) -> usize {
582        let mut size = 1;
583        size += if self.frame_counter_suppressed() {
584            0
585        } else {
586            4
587        };
588        size += if let Some(len) = self.key_identifier_length() {
589            len as usize
590        } else {
591            0
592        };
593        size
594    }
595
596    /// Return the index where the payload starts.
597    fn payload_start(&self) -> usize {
598        let mut index = self.aux_security_header_start();
599
600        if self.security_enabled() {
601            index += self.security_header_len();
602        }
603
604        index
605    }
606
607    /// Return the length of the key identifier field.
608    fn key_identifier_length(&self) -> Option<u8> {
609        Some(match self.key_identifier_mode() {
610            0 => 0,
611            1 => 1,
612            2 => 5,
613            3 => 9,
614            _ => return None,
615        })
616    }
617
618    /// Return the security level of the auxiliary security header.
619    pub fn security_level(&self) -> u8 {
620        let index = self.aux_security_header_start();
621        let b = self.buffer.as_ref()[index..][0];
622        b & 0b111
623    }
624
625    /// Return the key identifier mode used by the auxiliary security header.
626    pub fn key_identifier_mode(&self) -> u8 {
627        let index = self.aux_security_header_start();
628        let b = self.buffer.as_ref()[index..][0];
629        (b >> 3) & 0b11
630    }
631
632    /// Return `true` when the frame counter in the security header is suppressed.
633    pub fn frame_counter_suppressed(&self) -> bool {
634        let index = self.aux_security_header_start();
635        let b = self.buffer.as_ref()[index..][0];
636        ((b >> 5) & 0b1) == 0b1
637    }
638
639    /// Return the frame counter field.
640    pub fn frame_counter(&self) -> Option<u32> {
641        if self.frame_counter_suppressed() {
642            None
643        } else {
644            let index = self.aux_security_header_start();
645            let b = &self.buffer.as_ref()[index..];
646            Some(LittleEndian::read_u32(&b[1..1 + 4]))
647        }
648    }
649
650    /// Return the Key Identifier field.
651    fn key_identifier(&self) -> &[u8] {
652        let index = self.aux_security_header_start();
653        let b = &self.buffer.as_ref()[index..];
654        let length = if let Some(len) = self.key_identifier_length() {
655            len as usize
656        } else {
657            0
658        };
659        &b[5..][..length]
660    }
661
662    /// Return the Key Source field.
663    pub fn key_source(&self) -> Option<&[u8]> {
664        let ki = self.key_identifier();
665        let len = ki.len();
666        if len > 1 { Some(&ki[..len - 1]) } else { None }
667    }
668
669    /// Return the Key Index field.
670    pub fn key_index(&self) -> Option<u8> {
671        let ki = self.key_identifier();
672        let len = ki.len();
673
674        if len > 0 { Some(ki[len - 1]) } else { None }
675    }
676
677    /// Return the Message Integrity Code (MIC).
678    pub fn message_integrity_code(&self) -> Option<&[u8]> {
679        let mic_len = match self.security_level() {
680            0 | 4 => return None,
681            1 | 5 => 4,
682            2 | 6 => 8,
683            3 | 7 => 16,
684            _ => panic!(),
685        };
686
687        let data = &self.buffer.as_ref();
688        let len = data.len();
689
690        Some(&data[len - mic_len..])
691    }
692
693    /// Return the MAC header.
694    pub fn mac_header(&self) -> &[u8] {
695        let data = &self.buffer.as_ref();
696        &data[..self.payload_start()]
697    }
698}
699
700impl<'a, T: AsRef<[u8]> + ?Sized> Frame<&'a T> {
701    /// Return a pointer to the payload.
702    #[inline]
703    pub fn payload(&self) -> Option<&'a [u8]> {
704        match self.frame_type() {
705            FrameType::Data => {
706                let index = self.payload_start();
707                let data = &self.buffer.as_ref();
708
709                Some(&data[index..])
710            }
711            _ => None,
712        }
713    }
714}
715
716impl<T: AsRef<[u8]> + AsMut<[u8]>> Frame<T> {
717    /// Set the frame type.
718    #[inline]
719    pub fn set_frame_type(&mut self, frame_type: FrameType) {
720        let data = &mut self.buffer.as_mut()[field::FRAMECONTROL];
721        let mut raw = LittleEndian::read_u16(data);
722
723        raw = (raw & !(0b111)) | (u8::from(frame_type) as u16 & 0b111);
724        data.copy_from_slice(&raw.to_le_bytes());
725    }
726
727    set_fc_bit_field!(set_security_enabled, 3);
728    set_fc_bit_field!(set_frame_pending, 4);
729    set_fc_bit_field!(set_ack_request, 5);
730    set_fc_bit_field!(set_pan_id_compression, 6);
731
732    /// Set the frame version.
733    #[inline]
734    pub fn set_frame_version(&mut self, version: FrameVersion) {
735        let data = &mut self.buffer.as_mut()[field::FRAMECONTROL];
736        let mut raw = LittleEndian::read_u16(data);
737
738        raw = (raw & !(0b11 << 12)) | ((u8::from(version) as u16 & 0b11) << 12);
739        data.copy_from_slice(&raw.to_le_bytes());
740    }
741
742    /// Set the frame sequence number.
743    #[inline]
744    pub fn set_sequence_number(&mut self, value: u8) {
745        let data = self.buffer.as_mut();
746        data[field::SEQUENCE_NUMBER] = value;
747    }
748
749    /// Set the destination PAN ID.
750    #[inline]
751    pub fn set_dst_pan_id(&mut self, value: Pan) {
752        // NOTE the destination addressing mode must be different than Absent.
753        // This is the reason why we set it to Extended.
754        self.set_dst_addressing_mode(AddressingMode::Extended);
755
756        let data = self.buffer.as_mut();
757        data[field::ADDRESSING][..2].copy_from_slice(&value.as_bytes());
758    }
759
760    /// Set the destination address.
761    #[inline]
762    pub fn set_dst_addr(&mut self, value: Address) {
763        match value {
764            Address::Absent => self.set_dst_addressing_mode(AddressingMode::Absent),
765            Address::Short(mut value) => {
766                value.reverse();
767                self.set_dst_addressing_mode(AddressingMode::Short);
768                let data = self.buffer.as_mut();
769                data[field::ADDRESSING][2..2 + 2].copy_from_slice(&value);
770                value.reverse();
771            }
772            Address::Extended(mut value) => {
773                value.reverse();
774                self.set_dst_addressing_mode(AddressingMode::Extended);
775                let data = &mut self.buffer.as_mut()[field::ADDRESSING];
776                data[2..2 + 8].copy_from_slice(&value);
777                value.reverse();
778            }
779        }
780    }
781
782    /// Set the destination addressing mode.
783    #[inline]
784    fn set_dst_addressing_mode(&mut self, value: AddressingMode) {
785        let data = &mut self.buffer.as_mut()[field::FRAMECONTROL];
786        let mut raw = LittleEndian::read_u16(data);
787
788        raw = (raw & !(0b11 << 10)) | ((u8::from(value) as u16 & 0b11) << 10);
789        data.copy_from_slice(&raw.to_le_bytes());
790    }
791
792    /// Set the source PAN ID.
793    #[inline]
794    pub fn set_src_pan_id(&mut self, value: Pan) {
795        let offset = match self.dst_addressing_mode() {
796            AddressingMode::Absent => 0,
797            AddressingMode::Short => 2,
798            AddressingMode::Extended => 8,
799            _ => unreachable!(),
800        } + 2;
801
802        let data = &mut self.buffer.as_mut()[field::ADDRESSING];
803        data[offset..offset + 2].copy_from_slice(&value.as_bytes());
804    }
805
806    /// Set the source address.
807    #[inline]
808    pub fn set_src_addr(&mut self, value: Address) {
809        let offset = match self.dst_addressing_mode() {
810            AddressingMode::Absent => 0,
811            AddressingMode::Short => 2,
812            AddressingMode::Extended => 8,
813            _ => unreachable!(),
814        } + 2;
815
816        let offset = offset + if self.pan_id_compression() { 0 } else { 2 };
817
818        match value {
819            Address::Absent => self.set_src_addressing_mode(AddressingMode::Absent),
820            Address::Short(mut value) => {
821                value.reverse();
822                self.set_src_addressing_mode(AddressingMode::Short);
823                let data = &mut self.buffer.as_mut()[field::ADDRESSING];
824                data[offset..offset + 2].copy_from_slice(&value);
825                value.reverse();
826            }
827            Address::Extended(mut value) => {
828                value.reverse();
829                self.set_src_addressing_mode(AddressingMode::Extended);
830                let data = &mut self.buffer.as_mut()[field::ADDRESSING];
831                data[offset..offset + 8].copy_from_slice(&value);
832                value.reverse();
833            }
834        }
835    }
836
837    /// Set the source addressing mode.
838    #[inline]
839    fn set_src_addressing_mode(&mut self, value: AddressingMode) {
840        let data = &mut self.buffer.as_mut()[field::FRAMECONTROL];
841        let mut raw = LittleEndian::read_u16(data);
842
843        raw = (raw & !(0b11 << 14)) | ((u8::from(value) as u16 & 0b11) << 14);
844        data.copy_from_slice(&raw.to_le_bytes());
845    }
846
847    /// Return a mutable pointer to the payload.
848    #[inline]
849    pub fn payload_mut(&mut self) -> Option<&mut [u8]> {
850        match self.frame_type() {
851            FrameType::Data => {
852                let index = self.payload_start();
853                let data = self.buffer.as_mut();
854                Some(&mut data[index..])
855            }
856            _ => None,
857        }
858    }
859}
860
861impl<T: AsRef<[u8]>> fmt::Display for Frame<T> {
862    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
863        write!(f, "IEEE802.15.4 frame type={}", self.frame_type())?;
864
865        if let Some(seq) = self.sequence_number() {
866            write!(f, " seq={:02x}", seq)?;
867        }
868
869        if let Some(pan) = self.dst_pan_id() {
870            write!(f, " dst-pan={}", pan)?;
871        }
872
873        if let Some(pan) = self.src_pan_id() {
874            write!(f, " src-pan={}", pan)?;
875        }
876
877        if let Some(addr) = self.dst_addr() {
878            write!(f, " dst={}", addr)?;
879        }
880
881        if let Some(addr) = self.src_addr() {
882            write!(f, " src={}", addr)?;
883        }
884
885        Ok(())
886    }
887}
888
889#[cfg(feature = "defmt")]
890impl<T: AsRef<[u8]>> defmt::Format for Frame<T> {
891    fn format(&self, f: defmt::Formatter) {
892        defmt::write!(f, "IEEE802.15.4 frame type={}", self.frame_type());
893
894        if let Some(seq) = self.sequence_number() {
895            defmt::write!(f, " seq={:02x}", seq);
896        }
897
898        if let Some(pan) = self.dst_pan_id() {
899            defmt::write!(f, " dst-pan={}", pan);
900        }
901
902        if let Some(pan) = self.src_pan_id() {
903            defmt::write!(f, " src-pan={}", pan);
904        }
905
906        if let Some(addr) = self.dst_addr() {
907            defmt::write!(f, " dst={}", addr);
908        }
909
910        if let Some(addr) = self.src_addr() {
911            defmt::write!(f, " src={}", addr);
912        }
913    }
914}
915
916/// A high-level representation of an IEEE802.15.4 frame.
917#[derive(Debug, PartialEq, Eq, Clone, Copy)]
918#[cfg_attr(feature = "defmt", derive(defmt::Format))]
919pub struct Repr {
920    pub frame_type: FrameType,
921    pub security_enabled: bool,
922    pub frame_pending: bool,
923    pub ack_request: bool,
924    pub sequence_number: Option<u8>,
925    pub pan_id_compression: bool,
926    pub frame_version: FrameVersion,
927    pub dst_pan_id: Option<Pan>,
928    pub dst_addr: Option<Address>,
929    pub src_pan_id: Option<Pan>,
930    pub src_addr: Option<Address>,
931}
932
933impl Repr {
934    /// Parse an IEEE 802.15.4 frame and return a high-level representation.
935    pub fn parse<T: AsRef<[u8]> + ?Sized>(packet: &Frame<&T>) -> Result<Repr> {
936        // Ensure the basic accessors will work.
937        packet.check_len()?;
938
939        Ok(Repr {
940            frame_type: packet.frame_type(),
941            security_enabled: packet.security_enabled(),
942            frame_pending: packet.frame_pending(),
943            ack_request: packet.ack_request(),
944            sequence_number: packet.sequence_number(),
945            pan_id_compression: packet.pan_id_compression(),
946            frame_version: packet.frame_version(),
947            dst_pan_id: packet.dst_pan_id(),
948            dst_addr: packet.dst_addr(),
949            src_pan_id: packet.src_pan_id(),
950            src_addr: packet.src_addr(),
951        })
952    }
953
954    /// Return the length of a buffer required to hold a packet with the payload of a given length.
955    #[inline]
956    pub const fn buffer_len(&self) -> usize {
957        3 + 2
958            + match self.dst_addr {
959                Some(Address::Absent) | None => 0,
960                Some(Address::Short(_)) => 2,
961                Some(Address::Extended(_)) => 8,
962            }
963            + if !self.pan_id_compression { 2 } else { 0 }
964            + match self.src_addr {
965                Some(Address::Absent) | None => 0,
966                Some(Address::Short(_)) => 2,
967                Some(Address::Extended(_)) => 8,
968            }
969    }
970
971    /// Emit a high-level representation into an IEEE802.15.4 frame.
972    pub fn emit<T: AsRef<[u8]> + AsMut<[u8]>>(&self, frame: &mut Frame<T>) {
973        frame.set_frame_type(self.frame_type);
974        frame.set_security_enabled(self.security_enabled);
975        frame.set_frame_pending(self.frame_pending);
976        frame.set_ack_request(self.ack_request);
977        frame.set_pan_id_compression(self.pan_id_compression);
978        frame.set_frame_version(self.frame_version);
979
980        if let Some(sequence_number) = self.sequence_number {
981            frame.set_sequence_number(sequence_number);
982        }
983
984        if let Some(dst_pan_id) = self.dst_pan_id {
985            frame.set_dst_pan_id(dst_pan_id);
986        }
987        if let Some(dst_addr) = self.dst_addr {
988            frame.set_dst_addr(dst_addr);
989        }
990
991        if !self.pan_id_compression && self.src_pan_id.is_some() {
992            frame.set_src_pan_id(self.src_pan_id.unwrap());
993        }
994
995        if let Some(src_addr) = self.src_addr {
996            frame.set_src_addr(src_addr);
997        }
998    }
999}
1000
1001#[cfg(test)]
1002mod test {
1003    use super::*;
1004
1005    #[test]
1006    fn test_broadcast() {
1007        assert!(Address::BROADCAST.is_broadcast());
1008        assert!(!Address::BROADCAST.is_unicast());
1009    }
1010
1011    #[test]
1012    fn prepare_frame() {
1013        let mut buffer = [0u8; 128];
1014
1015        let repr = Repr {
1016            frame_type: FrameType::Data,
1017            security_enabled: false,
1018            frame_pending: false,
1019            ack_request: true,
1020            pan_id_compression: true,
1021            frame_version: FrameVersion::Ieee802154,
1022            sequence_number: Some(1),
1023            dst_pan_id: Some(Pan(0xabcd)),
1024            dst_addr: Some(Address::BROADCAST),
1025            src_pan_id: None,
1026            src_addr: Some(Address::Extended([
1027                0xc7, 0xd9, 0xb5, 0x14, 0x00, 0x4b, 0x12, 0x00,
1028            ])),
1029        };
1030
1031        let buffer_len = repr.buffer_len();
1032
1033        let mut frame = Frame::new_unchecked(&mut buffer[..buffer_len]);
1034        repr.emit(&mut frame);
1035
1036        println!("{frame:2x?}");
1037
1038        assert_eq!(frame.frame_type(), FrameType::Data);
1039        assert!(!frame.security_enabled());
1040        assert!(!frame.frame_pending());
1041        assert!(frame.ack_request());
1042        assert!(frame.pan_id_compression());
1043        assert_eq!(frame.frame_version(), FrameVersion::Ieee802154);
1044        assert_eq!(frame.sequence_number(), Some(1));
1045        assert_eq!(frame.dst_pan_id(), Some(Pan(0xabcd)));
1046        assert_eq!(frame.dst_addr(), Some(Address::BROADCAST));
1047        assert_eq!(frame.src_pan_id(), None);
1048        assert_eq!(
1049            frame.src_addr(),
1050            Some(Address::Extended([
1051                0xc7, 0xd9, 0xb5, 0x14, 0x00, 0x4b, 0x12, 0x00
1052            ]))
1053        );
1054    }
1055
1056    macro_rules! vector_test {
1057        ($name:ident $bytes:expr ; $($test_method:ident -> $expected:expr,)*) => {
1058            #[test]
1059            #[allow(clippy::bool_assert_comparison)]
1060            fn $name() -> Result<()> {
1061                let frame = &$bytes;
1062                let frame = Frame::new_checked(frame)?;
1063
1064                $(
1065                    assert_eq!(frame.$test_method(), $expected, stringify!($test_method));
1066                )*
1067
1068                Ok(())
1069            }
1070        }
1071    }
1072
1073    vector_test! {
1074        extended_addr
1075        [
1076            0b0000_0001, 0b1100_1100, // frame control
1077            0b0, // seq
1078            0xcd, 0xab, // pan id
1079            0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, // dst addr
1080            0x03, 0x04, // pan id
1081            0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, // src addr
1082        ];
1083        frame_type -> FrameType::Data,
1084        dst_addr -> Some(Address::Extended([0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00])),
1085        src_addr -> Some(Address::Extended([0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00])),
1086        dst_pan_id -> Some(Pan(0xabcd)),
1087    }
1088
1089    vector_test! {
1090        short_addr
1091        [
1092            0x01, 0x98,             // frame control
1093            0x00,                   // sequence number
1094            0x34, 0x12, 0x78, 0x56, // PAN identifier and address of destination
1095            0x34, 0x12, 0xbc, 0x9a, // PAN identifier and address of source
1096        ];
1097        frame_type -> FrameType::Data,
1098        security_enabled -> false,
1099        frame_pending -> false,
1100        ack_request -> false,
1101        pan_id_compression -> false,
1102        dst_addressing_mode -> AddressingMode::Short,
1103        frame_version -> FrameVersion::Ieee802154_2006,
1104        src_addressing_mode -> AddressingMode::Short,
1105        dst_pan_id -> Some(Pan(0x1234)),
1106        dst_addr -> Some(Address::Short([0x56, 0x78])),
1107        src_pan_id -> Some(Pan(0x1234)),
1108        src_addr -> Some(Address::Short([0x9a, 0xbc])),
1109    }
1110
1111    vector_test! {
1112        zolertia_remote
1113        [
1114            0x41, 0xd8, // frame control
1115            0x01, // sequence number
1116            0xcd, 0xab, // Destination PAN id
1117            0xff, 0xff, // Short destination address
1118            0xc7, 0xd9, 0xb5, 0x14, 0x00, 0x4b, 0x12, 0x00, // Extended source address
1119            0x2b, 0x00, 0x00, 0x00, // payload
1120        ];
1121        frame_type -> FrameType::Data,
1122        security_enabled -> false,
1123        frame_pending -> false,
1124        ack_request -> false,
1125        pan_id_compression -> true,
1126        dst_addressing_mode -> AddressingMode::Short,
1127        frame_version -> FrameVersion::Ieee802154_2006,
1128        src_addressing_mode -> AddressingMode::Extended,
1129        payload -> Some(&[0x2b, 0x00, 0x00, 0x00][..]),
1130    }
1131
1132    vector_test! {
1133        security
1134        [
1135            0x69,0xdc, // frame control
1136            0x32, // sequence number
1137            0xcd,0xab, // destination PAN id
1138            0xbf,0x9b,0x15,0x06,0x00,0x4b,0x12,0x00, // extended destination address
1139            0xc7,0xd9,0xb5,0x14,0x00,0x4b,0x12,0x00, // extended source address
1140            0x05, // security control field
1141            0x31,0x01,0x00,0x00, // frame counter
1142            0x3e,0xe8,0xfb,0x85,0xe4,0xcc,0xf4,0x48,0x90,0xfe,0x56,0x66,0xf7,0x1c,0x65,0x9e,0xf9, // data
1143            0x93,0xc8,0x34,0x2e,// MIC
1144        ];
1145        frame_type -> FrameType::Data,
1146        security_enabled -> true,
1147        frame_pending -> false,
1148        ack_request -> true,
1149        pan_id_compression -> true,
1150        dst_addressing_mode -> AddressingMode::Extended,
1151        frame_version -> FrameVersion::Ieee802154_2006,
1152        src_addressing_mode -> AddressingMode::Extended,
1153        dst_pan_id -> Some(Pan(0xabcd)),
1154        dst_addr -> Some(Address::Extended([0x00,0x12,0x4b,0x00,0x06,0x15,0x9b,0xbf])),
1155        src_pan_id -> None,
1156        src_addr -> Some(Address::Extended([0x00,0x12,0x4b,0x00,0x14,0xb5,0xd9,0xc7])),
1157        security_level -> 5,
1158        key_identifier_mode -> 0,
1159        frame_counter -> Some(305),
1160        key_source -> None,
1161        key_index -> None,
1162        payload -> Some(&[0x3e,0xe8,0xfb,0x85,0xe4,0xcc,0xf4,0x48,0x90,0xfe,0x56,0x66,0xf7,0x1c,0x65,0x9e,0xf9,0x93,0xc8,0x34,0x2e][..]),
1163        message_integrity_code -> Some(&[0x93, 0xC8, 0x34, 0x2E][..]),
1164        mac_header -> &[
1165            0x69,0xdc, // frame control
1166            0x32, // sequence number
1167            0xcd,0xab, // destination PAN id
1168            0xbf,0x9b,0x15,0x06,0x00,0x4b,0x12,0x00, // extended destination address
1169            0xc7,0xd9,0xb5,0x14,0x00,0x4b,0x12,0x00, // extended source address
1170            0x05, // security control field
1171            0x31,0x01,0x00,0x00, // frame counter
1172        ][..],
1173    }
1174}