ieee802154/mac/frame/
header.rs

1//! Partial implementation of the IEEE 802.15.4 frame Header
2//!
3//! The main type in this module is [`Header`], the header of 802.15.4 MAC frame.
4//!
5//! [`Header`]: struct.Header.html
6
7use byte::{check_len, BytesExt, TryRead, TryWrite, LE};
8use cipher::{consts::U16, BlockCipher, NewBlockCipher};
9use hash32_derive::Hash32;
10
11pub use super::frame_control::{AddressMode, FrameType, FrameVersion};
12use super::DecodeError;
13use super::{
14    frame_control::{mask, offset},
15    security::{KeyDescriptorLookup, SecurityContext},
16};
17use super::{security::AuxiliarySecurityHeader, EncodeError};
18
19/// MAC frame header
20///
21/// External documentation for [MAC frame format start at 5.2]
22///
23/// [MAC frame format start at 5.2]: http://ecee.colorado.edu/~liue/teaching/comm_standards/2015S_zigbee/802.15.4-2011.pdf
24#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
25#[cfg_attr(feature = "defmt", derive(defmt::Format))]
26pub struct Header {
27    // * Frame Control Field * /
28    /// Frame Type
29    pub frame_type: FrameType,
30
31    /// Frame Pending
32    ///
33    /// The Frame Pending field shall be set to `true` if the device sending the frame has more data
34    /// for the recipient,as described in 5.1.6.3. This field shall be set to `false` otherwise.
35    pub frame_pending: bool,
36
37    /// Acknowledgement Request
38    ///
39    /// The AR field specifies whether an acknowledgment is required from the recipient device on receipt of a data
40    /// or MAC command frame. If this field is set to `true`, the recipient device shall send an acknowledgment frame
41    /// only if, upon reception, the frame passes the filtering described in 5.1.6.2. If this field is set to `false`, the
42    /// recipient device shall not send an acknowledgment frame.
43    pub ack_request: bool,
44
45    /// PAN ID Compress
46    ///
47    /// The PAN ID Compression field specifies whether the MAC frame is to be sent containing only one of the
48    /// PAN identifier fields when both src and destination addresses are present. If this field is set to `true` and
49    /// both  the  src  and  destination  addresses  are  present,  the  frame  shall  contain  only  the  Destination  PAN
50    /// Identifier field, and the Source PAN Identifier field shall be assumed equal to that of the destination. If this
51    /// field is set to `false`, then the PAN Identifier field shall be present if and only if the corresponding address is
52    /// present.
53    pub pan_id_compress: bool,
54
55    /// Suppress sequence number
56    pub seq_no_suppress: bool,
57
58    /// Information element present
59    pub ie_present: bool,
60
61    /// Frame version
62    pub version: FrameVersion,
63
64    // Destination address mode
65    // use `destination` to determinate AddressMode
66
67    // Source address mode
68    // use `source` to determinate AddressMode
69
70    // * End of Frame Control Field */
71    /// Sequence Number
72    pub seq: u8,
73
74    /// Destination Address
75    pub destination: Option<Address>,
76
77    /// Source Address
78    pub source: Option<Address>,
79
80    /// Auxiliary security header. If security is enabled in this header,
81    /// this field will be Some, else it will be None
82    pub auxiliary_security_header: Option<AuxiliarySecurityHeader>,
83}
84
85impl Header {
86    /// Get the size of this header in octets
87    pub fn get_octet_size(&self) -> usize {
88        // Frame control + sequence number
89        let mut len = 3;
90
91        for i in [self.destination, self.source].iter() {
92            match i {
93                Some(addr) => {
94                    // pan ID
95                    len += 2;
96                    // Address length
97                    match addr {
98                        Address::Short(..) => len += 2,
99                        Address::Extended(..) => len += 8,
100                    }
101                }
102                _ => {}
103            }
104        }
105        len
106    }
107
108    /// Whether this header has security enabled
109    pub fn has_security(&self) -> bool {
110        self.auxiliary_security_header.is_some()
111    }
112}
113
114impl TryRead<'_> for Header {
115    fn try_read(bytes: &[u8], _ctx: ()) -> byte::Result<(Self, usize)> {
116        let offset = &mut 0;
117        // Make sure we have enough buffer for the Frame Control field
118        check_len(&bytes, 3)?;
119
120        /* Decode Frame Control Field */
121        let bits: u16 = bytes.read_with(offset, LE)?;
122
123        let frame_type =
124            ((bits & mask::FRAME_TYPE) >> offset::FRAME_TYPE) as u8;
125        let security = ((bits & mask::SECURITY) >> offset::SECURITY) as u8;
126
127        let frame_pending = ((bits & mask::PENDING) >> offset::PENDING) as u8;
128        let ack_request = ((bits & mask::ACK) >> offset::ACK) as u8;
129        let pan_id_compress =
130            ((bits & mask::PAN_ID_COMPRESS) >> offset::PAN_ID_COMPRESS) as u8;
131
132        let seq_no_suppress =
133            ((bits & mask::SEQ_NO_SUPPRESS) >> offset::SEQ_NO_SUPPRESS) as u8;
134        let ie_present =
135            ((bits & mask::IE_PRESENT) >> offset::IE_PRESENT) as u8;
136
137        let dest_addr_mode =
138            ((bits & mask::DEST_ADDR_MODE) >> offset::DEST_ADDR_MODE) as u8;
139
140        let version = ((bits & mask::VERSION) >> offset::VERSION) as u8;
141        let src_addr_mode =
142            ((bits & mask::SRC_ADDR_MODE) >> offset::SRC_ADDR_MODE) as u8;
143
144        let version = FrameVersion::from_bits(version)
145            .ok_or(DecodeError::InvalidFrameVersion(version))?;
146        let frame_type = FrameType::from_bits(frame_type)
147            .ok_or(DecodeError::InvalidFrameType(frame_type))?;
148        let dest_addr_mode = AddressMode::from_bits(dest_addr_mode)?;
149        let src_addr_mode = AddressMode::from_bits(src_addr_mode)?;
150
151        // make bool values
152        let security = security > 0;
153        let frame_pending = frame_pending > 0;
154        let ack_request = ack_request > 0;
155        let pan_id_compress = pan_id_compress > 0;
156        let seq_no_suppress = seq_no_suppress > 0;
157        let ie_present = ie_present > 0;
158
159        /* Decode header depending on Frame Control Fields */
160
161        let seq = bytes.read(offset)?;
162
163        let destination = match dest_addr_mode {
164            AddressMode::None => None,
165            AddressMode::Short => {
166                Some(Address::Short(bytes.read(offset)?, bytes.read(offset)?))
167            }
168            AddressMode::Extended => Some(Address::Extended(
169                bytes.read(offset)?,
170                bytes.read(offset)?,
171            )),
172        };
173
174        if pan_id_compress {
175            destination.ok_or(byte::Error::BadInput {
176                err: "InvalidAddressMode",
177            })?;
178        }
179
180        let source = match src_addr_mode {
181            AddressMode::None => None,
182            AddressMode::Short => {
183                if pan_id_compress {
184                    Some(Address::Short(
185                        destination.unwrap().pan_id(),
186                        bytes.read(offset)?,
187                    ))
188                } else {
189                    Some(Address::Short(
190                        bytes.read(offset)?,
191                        bytes.read(offset)?,
192                    ))
193                }
194            }
195            AddressMode::Extended => {
196                if pan_id_compress {
197                    Some(Address::Extended(
198                        destination.unwrap().pan_id(),
199                        bytes.read(offset)?,
200                    ))
201                } else {
202                    Some(Address::Extended(
203                        bytes.read(offset)?,
204                        bytes.read(offset)?,
205                    ))
206                }
207            }
208        };
209
210        let auxiliary_security_header = match security {
211            true => Some(bytes.read(offset)?),
212            false => None,
213        };
214
215        let header = Header {
216            frame_type,
217            frame_pending,
218            ack_request,
219            pan_id_compress,
220            seq_no_suppress,
221            ie_present,
222            version,
223            seq,
224            destination,
225            source,
226            auxiliary_security_header,
227        };
228
229        Ok((header, *offset))
230    }
231}
232
233impl<AEADBLKCIPH, KEYDESCLO>
234    TryWrite<&Option<&mut SecurityContext<AEADBLKCIPH, KEYDESCLO>>> for Header
235where
236    AEADBLKCIPH: NewBlockCipher + BlockCipher<BlockSize = U16>,
237    KEYDESCLO: KeyDescriptorLookup<AEADBLKCIPH::KeySize>,
238{
239    fn try_write(
240        self,
241        bytes: &mut [u8],
242        sec_ctx: &Option<&mut SecurityContext<AEADBLKCIPH, KEYDESCLO>>,
243    ) -> byte::Result<usize> {
244        let offset = &mut 0;
245        let dest_addr_mode = AddressMode::from(self.destination);
246        let src_addr_mode = AddressMode::from(self.source);
247
248        let security = self.auxiliary_security_header.is_some();
249
250        let frame_control_raw = (self.frame_type as u16) << offset::FRAME_TYPE
251            | (security as u16) << offset::SECURITY
252            | (self.frame_pending as u16) << offset::PENDING
253            | (self.ack_request as u16) << offset::ACK
254            | (self.pan_id_compress as u16) << offset::PAN_ID_COMPRESS
255            | (dest_addr_mode as u16) << offset::DEST_ADDR_MODE
256            | (self.version as u16) << offset::VERSION
257            | (src_addr_mode as u16) << offset::SRC_ADDR_MODE;
258
259        bytes.write_with(offset, frame_control_raw, LE)?;
260
261        // Write Sequence Number
262        bytes.write(offset, self.seq)?;
263
264        if (self.destination.is_none() || self.source.is_none())
265            && self.pan_id_compress
266        {
267            return Err(EncodeError::DisallowedPanIdCompress)?;
268        }
269
270        // Write addresses
271        if let Some(destination) = self.destination {
272            bytes.write_with(offset, destination, AddressEncoding::Normal)?;
273        }
274
275        match (self.source, self.pan_id_compress) {
276            (Some(source), true) => {
277                bytes.write_with(
278                    offset,
279                    source,
280                    AddressEncoding::Compressed,
281                )?;
282            }
283            (Some(source), false) => {
284                bytes.write_with(offset, source, AddressEncoding::Normal)?;
285            }
286            (None, true) => {
287                panic!("frame control request compress source address without contain this address")
288            }
289            (None, false) => (),
290        }
291
292        if security && sec_ctx.is_none() {
293            return Err(EncodeError::MissingSecurityCtx)?;
294        } else if security {
295            match self.auxiliary_security_header {
296                Some(aux_sec_head) => match sec_ctx {
297                    Some(sec_ctx) => {
298                        bytes.write_with(offset, aux_sec_head, sec_ctx)?;
299                    }
300                    None => return Err(EncodeError::UnknownError)?,
301                },
302                None => return Err(EncodeError::UnknownError)?,
303            }
304        }
305        Ok(*offset)
306    }
307}
308
309/// Personal Area Network Identifier
310///
311/// A 16-bit value that identifies a PAN
312///
313/// # Example
314///
315/// ``` rust
316/// use ieee802154::mac::PanId;
317///
318/// let pan_id = PanId(0x0123);
319/// ```
320#[derive(Clone, Copy, Debug, Eq, Hash, Hash32, PartialEq)]
321#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
322#[cfg_attr(feature = "defmt", derive(defmt::Format))]
323pub struct PanId(pub u16);
324
325impl PanId {
326    /// Get the broadcast PAN identifier
327    pub fn broadcast() -> Self {
328        Self(0xffff)
329    }
330}
331
332impl TryWrite for PanId {
333    fn try_write(self, bytes: &mut [u8], _ctx: ()) -> byte::Result<usize> {
334        let offset = &mut 0;
335        bytes.write_with(offset, self.0, LE)?;
336        Ok(*offset)
337    }
338}
339
340impl TryRead<'_> for PanId {
341    fn try_read(bytes: &[u8], _ctx: ()) -> byte::Result<(Self, usize)> {
342        let offset = &mut 0;
343        Ok((Self(bytes.read_with(offset, LE)?), *offset))
344    }
345}
346
347/// A 16-bit short address
348///
349/// Short address assigned to a device during association, used to identify the
350/// device in the PAN.
351///
352/// # Example
353///
354/// ``` rust
355/// use ieee802154::mac::ShortAddress;
356///
357/// let short_address = ShortAddress(0x0123);
358/// ```
359#[derive(Clone, Copy, Debug, Eq, Hash, Hash32, PartialEq)]
360#[cfg_attr(feature = "defmt", derive(defmt::Format))]
361#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
362
363pub struct ShortAddress(pub u16);
364
365impl ShortAddress {
366    /// An instance of `ShortAddress` that represents the broadcast address.
367    pub const BROADCAST: Self = ShortAddress(0xffff);
368
369    /// Creates an instance of `ShortAddress` that represents the broadcast address
370    pub fn broadcast() -> Self {
371        ShortAddress(0xffff)
372    }
373}
374
375impl TryWrite for ShortAddress {
376    fn try_write(self, bytes: &mut [u8], _ctx: ()) -> byte::Result<usize> {
377        let offset = &mut 0;
378        bytes.write_with(offset, self.0, LE)?;
379        Ok(*offset)
380    }
381}
382
383impl TryRead<'_> for ShortAddress {
384    fn try_read(bytes: &[u8], _ctx: ()) -> byte::Result<(Self, usize)> {
385        let offset = &mut 0;
386        Ok((Self(bytes.read_with(offset, LE)?), *offset))
387    }
388}
389
390/// A 64-bit extended address
391///
392/// A unique address that is used to identify an device in the PAN.
393///
394/// # Example
395///
396/// ``` rust
397/// use ieee802154::mac::ExtendedAddress;
398///
399/// let ext_address = ExtendedAddress(0x0123456789abcdef);
400/// ```
401#[derive(Clone, Copy, Debug, Eq, Hash, Hash32, PartialEq)]
402#[cfg_attr(feature = "defmt", derive(defmt::Format))]
403#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
404
405pub struct ExtendedAddress(pub u64);
406
407impl ExtendedAddress {
408    /// An instance of `ExtendedAddress` that represents the broadcast address.
409    pub const BROADCAST: Self = ExtendedAddress(0xffffffffffffffffu64);
410
411    /// Creates an instance of `ExtendedAddress` that represents the broadcast address
412    pub fn broadcast() -> Self {
413        ExtendedAddress(0xffffffffffffffffu64)
414    }
415}
416
417impl TryWrite for ExtendedAddress {
418    fn try_write(self, bytes: &mut [u8], _ctx: ()) -> byte::Result<usize> {
419        let offset = &mut 0;
420        bytes.write_with(offset, self.0, LE)?;
421        Ok(*offset)
422    }
423}
424
425impl TryRead<'_> for ExtendedAddress {
426    fn try_read(bytes: &[u8], _ctx: ()) -> byte::Result<(Self, usize)> {
427        let offset = &mut 0;
428        Ok((Self(bytes.read_with(offset, LE)?), *offset))
429    }
430}
431
432/// An address that might contain an PAN ID and address
433#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
434#[cfg_attr(feature = "defmt", derive(defmt::Format))]
435#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
436pub enum Address {
437    /// Short (16-bit) address and PAN ID (16-bit)
438    Short(PanId, ShortAddress),
439    /// Extended (64-bit) address and PAN ID (16-bit)
440    Extended(PanId, ExtendedAddress),
441}
442
443#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
444#[cfg_attr(feature = "defmt", derive(defmt::Format))]
445enum AddressEncoding {
446    Normal,
447    Compressed,
448}
449
450impl TryWrite<AddressEncoding> for Address {
451    fn try_write(
452        self,
453        bytes: &mut [u8],
454        enc: AddressEncoding,
455    ) -> byte::Result<usize> {
456        let offset = &mut 0;
457        match (self, enc) {
458            (Address::Short(pan_id, addr), AddressEncoding::Normal) => {
459                bytes.write(offset, pan_id)?;
460                bytes.write(offset, addr)?;
461            }
462            (Address::Short(_pan_id, addr), AddressEncoding::Compressed) => {
463                bytes.write(offset, addr)?;
464            }
465            (Address::Extended(pan_id, addr), AddressEncoding::Normal) => {
466                bytes.write(offset, pan_id)?;
467                bytes.write(offset, addr)?;
468            }
469            (Address::Extended(_pan_id, addr), AddressEncoding::Compressed) => {
470                bytes.write(offset, addr)?;
471            }
472        }
473        Ok(*offset)
474    }
475}
476
477impl Address {
478    /// Creates an instance of `Address` that represents the broadcast address
479    pub fn broadcast(mode: &AddressMode) -> Option<Self> {
480        match mode {
481            AddressMode::None => None,
482            AddressMode::Short => Some(Address::Short(
483                PanId::broadcast(),
484                ShortAddress::broadcast(),
485            )),
486            AddressMode::Extended => Some(Address::Extended(
487                PanId::broadcast(),
488                ExtendedAddress::broadcast(),
489            )),
490        }
491    }
492
493    /// Get the PAN ID for this address
494    pub fn pan_id(&self) -> PanId {
495        match *self {
496            Address::Short(pan_id, _) => pan_id,
497            Address::Extended(pan_id, _) => pan_id,
498        }
499    }
500}