dot15d4_frame/repr/ie/
mod.rs

1mod headers;
2pub use headers::*;
3
4mod nested;
5pub use nested::*;
6
7mod payloads;
8pub use payloads::*;
9
10use super::super::{InformationElements, PayloadInformationElement};
11use super::Result;
12
13use heapless::Vec;
14
15/// A high-level representation of Information Elements.
16#[derive(Debug, Default)]
17pub struct InformationElementsRepr {
18    /// The header information elements.
19    pub header_information_elements: Vec<HeaderInformationElementRepr, 16>,
20    /// The payload information elements.
21    pub payload_information_elements: Vec<PayloadInformationElementRepr, 16>,
22}
23
24#[cfg(feature = "fuzz")]
25impl arbitrary::Arbitrary<'_> for InformationElementsRepr {
26    fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
27        let mut header_information_elements = Vec::new();
28        let mut payload_information_elements = Vec::new();
29
30        for _ in 0..u.int_in_range(0..=15)? {
31            header_information_elements
32                .push(HeaderInformationElementRepr::arbitrary(u)?)
33                .map_err(|_| arbitrary::Error::IncorrectFormat)?;
34        }
35
36        for _ in 0..u.int_in_range(0..=15)? {
37            payload_information_elements
38                .push(PayloadInformationElementRepr::arbitrary(u)?)
39                .map_err(|_| arbitrary::Error::IncorrectFormat)?;
40        }
41
42        Ok(Self {
43            header_information_elements,
44            payload_information_elements,
45        })
46    }
47}
48
49impl InformationElementsRepr {
50    /// Parse Information Elements.
51    pub fn parse(ie: InformationElements<&[u8]>) -> Result<Self> {
52        let mut header_information_elements = Vec::new();
53        let mut payload_information_elements = Vec::new();
54
55        for header_ie in ie.header_information_elements() {
56            if header_information_elements
57                .push(HeaderInformationElementRepr::parse(&header_ie)?)
58                .is_err()
59            {
60                break;
61            }
62        }
63
64        for payload_ie in ie.payload_information_elements() {
65            if payload_information_elements
66                .push(PayloadInformationElementRepr::parse(&payload_ie)?)
67                .is_err()
68            {
69                break;
70            };
71        }
72
73        Ok(Self {
74            header_information_elements,
75            payload_information_elements,
76        })
77    }
78
79    /// The header terminations required to emit the Information Elements.
80    /// The first bool is the HT1, the second is the HT2, and the third is the
81    /// PT.
82    fn header_terminations(&self, contains_payload: bool) -> (bool, bool, bool) {
83        match (
84            !self.header_information_elements.is_empty(),
85            !self.payload_information_elements.is_empty(),
86            contains_payload,
87        ) {
88            // No IE lists, so no terminations.
89            (false, false, false) => (false, false, false),
90            // Only header IE list. The end of the frame can be determined by the length of the
91            // frame.
92            (true, false, false) => (false, false, false),
93            // Only payload IE list. The HT1 is required to terminate the header IE list.
94            (false, true, false) => (true, false, false),
95            // Both IE lists. The HT1 is required to terminate the header IE list.
96            // The payload HT is optional.
97            (true, true, false) => (true, false, false),
98            // No IE lists, so no terminations.
99            (false, false, true) => (false, false, false),
100            // No payload IE list. The HT2 is required to terminate the header IE list.
101            (true, false, true) => (false, true, false),
102            // No header IE list. The HT1 is required to terminate the payload IE list.
103            // The payload HT is optional.
104            (false, true, true) => (true, false, true),
105            // Both IE lists. The HT1 is required to terminate the header IE list.
106            // The payload HT is optional.
107            (true, true, true) => (true, false, true),
108        }
109    }
110
111    /// The buffer length required to emit the Information Elements.
112    pub fn buffer_len(&self, contains_payload: bool) -> usize {
113        let mut len = 0;
114
115        let (ht1, ht2, pt) = self.header_terminations(contains_payload);
116
117        for ie in self.header_information_elements.iter() {
118            len += ie.buffer_len();
119        }
120
121        if ht1 {
122            len += HeaderInformationElementRepr::HeaderTermination1.buffer_len();
123        }
124
125        if ht2 {
126            len += HeaderInformationElementRepr::HeaderTermination1.buffer_len();
127        }
128
129        for ie in self.payload_information_elements.iter() {
130            len += ie.buffer_len();
131        }
132
133        if pt {
134            len += PayloadInformationElementRepr::PayloadTermination.buffer_len();
135        }
136
137        len
138    }
139
140    /// Emit the Information Elements into a buffer.
141    pub fn emit(&self, buffer: &mut [u8], contains_payload: bool) {
142        let mut offset = 0;
143
144        let (ht1, ht2, pt) = self.header_terminations(contains_payload);
145
146        for ie in self.header_information_elements.iter() {
147            ie.emit(&mut buffer[offset..][..ie.buffer_len()]);
148            offset += ie.buffer_len();
149        }
150
151        if ht1 {
152            HeaderInformationElementRepr::HeaderTermination1.emit(&mut buffer[offset..][..2]);
153            offset += 2;
154        }
155
156        if ht2 {
157            HeaderInformationElementRepr::HeaderTermination2.emit(&mut buffer[offset..][..2]);
158            offset += 2;
159        }
160
161        for ie in self.payload_information_elements.iter() {
162            ie.emit(&mut PayloadInformationElement::new_unchecked(
163                &mut buffer[offset..][..ie.buffer_len()],
164            ));
165            offset += ie.buffer_len();
166        }
167
168        if pt {
169            PayloadInformationElementRepr::PayloadTermination.emit(
170                &mut PayloadInformationElement::new_unchecked(&mut buffer[offset..][..2]),
171            );
172        }
173    }
174}