openthread/ot/types/
tlv.rs1use crate::ot::ParseError;
6use crate::prelude_internal::*;
7use std::io::Write;
8
9const TLV_ESCAPE_LENGTH: u8 = 255;
10
11#[derive(Debug)]
13#[allow(missing_docs)]
14pub enum MeshcopTlv<'a> {
15 NetworkName(NetworkName),
17 PanId(PanId),
18 Channel(u8, u16),
19
20 ActiveTimestamp(Timestamp),
22
23 PendingTimestamp(Timestamp),
25
26 DelayTimer(u32),
28 Unknown(u8, &'a [u8]),
29}
30
31impl<'a> MeshcopTlv<'a> {
32 pub fn get_type(&self) -> u8 {
34 match self {
35 MeshcopTlv::PanId(_) => OT_MESHCOP_TLV_PANID.try_into().unwrap(),
36 MeshcopTlv::Channel(_, _) => OT_MESHCOP_TLV_CHANNEL.try_into().unwrap(),
37 MeshcopTlv::NetworkName(_) => OT_MESHCOP_TLV_NETWORKNAME.try_into().unwrap(),
38 MeshcopTlv::ActiveTimestamp(_) => OT_MESHCOP_TLV_ACTIVETIMESTAMP.try_into().unwrap(),
39 MeshcopTlv::PendingTimestamp(_) => OT_MESHCOP_TLV_PENDINGTIMESTAMP.try_into().unwrap(),
40 MeshcopTlv::DelayTimer(_) => OT_MESHCOP_TLV_DELAYTIMER.try_into().unwrap(),
41 MeshcopTlv::Unknown(x, _) => *x,
42 }
43 }
44
45 pub fn value_len(&self) -> usize {
47 match self {
48 MeshcopTlv::PanId(_) => core::mem::size_of::<PanId>(),
49 MeshcopTlv::Channel(_, _) => core::mem::size_of::<u8>() + core::mem::size_of::<u16>(),
50 MeshcopTlv::NetworkName(x) => x.len(),
51 MeshcopTlv::ActiveTimestamp(_) => core::mem::size_of::<u64>(),
52 MeshcopTlv::PendingTimestamp(_) => core::mem::size_of::<u64>(),
53 MeshcopTlv::DelayTimer(_) => core::mem::size_of::<u32>(),
54 MeshcopTlv::Unknown(_, x) => x.len(),
55 }
56 }
57
58 pub fn value_as_u8(&self) -> Option<u8> {
60 if self.value_len() != core::mem::size_of::<u8>() {
61 return None;
62 }
63
64 let mut bytes = [0u8; 1];
65 self.write_value_to(&mut bytes.as_mut_slice()).ok()?;
66 Some(bytes[0])
67 }
68
69 pub fn value_as_u16(&self) -> Option<u16> {
71 if self.value_len() != core::mem::size_of::<u16>() {
72 return None;
73 }
74
75 let mut bytes = [0u8; 2];
76 self.write_value_to(&mut bytes.as_mut_slice()).ok()?;
77 Some(u16::from_le_bytes(bytes))
78 }
79
80 pub fn value_as_u32(&self) -> Option<u32> {
82 if self.value_len() != core::mem::size_of::<u32>() {
83 return None;
84 }
85
86 let mut bytes = [0u8; 4];
87 self.write_value_to(&mut bytes.as_mut_slice()).ok()?;
88 Some(u32::from_le_bytes(bytes))
89 }
90
91 pub fn value_as_u64(&self) -> Option<u64> {
93 if self.value_len() != core::mem::size_of::<u64>() {
94 return None;
95 }
96
97 let mut bytes = [0u8; 8];
98 self.write_value_to(&mut bytes.as_mut_slice()).ok()?;
99 Some(u64::from_le_bytes(bytes))
100 }
101
102 pub fn value_as_slice(&self) -> Option<&'_ [u8]> {
104 match self {
105 MeshcopTlv::NetworkName(x) => Some(x.as_slice()),
106 MeshcopTlv::Unknown(_, x) => Some(x),
107 _ => None,
108 }
109 }
110
111 #[allow(clippy::len_without_is_empty)]
113 pub fn len(&self) -> usize {
114 if self.value_len() > (TLV_ESCAPE_LENGTH as usize - 1) {
115 3 + self.value_len()
116 } else {
117 2 + self.value_len()
118 }
119 }
120
121 #[allow(clippy::unused_io_amount)] pub fn write_to<T: Write>(&self, out: &mut T) -> std::io::Result<()> {
126 let value_len = self.value_len();
127
128 if value_len > (TLV_ESCAPE_LENGTH as usize - 1) {
129 let value_len_le = u16::try_from(value_len).unwrap().to_le_bytes();
130 out.write(&[self.get_type()])?;
131 out.write(&value_len_le)?;
132 self.write_value_to(out)
133 } else {
134 out.write(&[self.get_type()])?;
135 out.write(&[value_len.try_into().unwrap()])?;
136 self.write_value_to(out)
137 }
138 }
139
140 pub fn write_value_to<T: Write>(&self, out: &mut T) -> std::io::Result<()> {
144 match self {
145 MeshcopTlv::NetworkName(x) => out.write_all(x.as_slice()),
146
147 MeshcopTlv::ActiveTimestamp(Timestamp(a_u64))
148 | MeshcopTlv::PendingTimestamp(Timestamp(a_u64)) => {
149 out.write_all(a_u64.to_le_bytes().as_slice())
150 }
151 MeshcopTlv::DelayTimer(a_u32) => out.write_all(a_u32.to_le_bytes().as_slice()),
152 MeshcopTlv::PanId(a_u16) => out.write_all(a_u16.to_le_bytes().as_slice()),
153 MeshcopTlv::Channel(page, index) => {
154 out.write_all(&[*page])?;
155 out.write_all(index.to_le_bytes().as_slice())
156 }
157 MeshcopTlv::Unknown(_, x) => out.write_all(x),
158 }
159 }
160
161 pub fn from_type_and_value(tlv_type: u8, value: &'a [u8]) -> MeshcopTlv<'a> {
163 match tlv_type as otMeshcopTlvType {
164 OT_MESHCOP_TLV_NETWORKNAME if value.len() <= (OT_NETWORK_NAME_MAX_SIZE as usize) => {
165 MeshcopTlv::NetworkName(NetworkName::try_from_slice(value).unwrap())
166 }
167 OT_MESHCOP_TLV_CHANNEL if value.len() == 3 => {
168 let mut bytes = [0u8; 2];
169 bytes.copy_from_slice(&value[1..]);
170 MeshcopTlv::Channel(value[0], u16::from_le_bytes(bytes))
171 }
172 OT_MESHCOP_TLV_PANID if value.len() == 2 => {
173 let mut bytes = [0u8; 2];
174 bytes.copy_from_slice(value);
175 MeshcopTlv::PanId(u16::from_le_bytes(bytes))
176 }
177 OT_MESHCOP_TLV_DELAYTIMER if value.len() == 4 => {
178 let mut bytes = [0u8; 4];
179 bytes.copy_from_slice(value);
180 MeshcopTlv::DelayTimer(u32::from_le_bytes(bytes))
181 }
182 OT_MESHCOP_TLV_ACTIVETIMESTAMP if value.len() == 8 => {
183 let mut bytes = [0u8; 8];
184 bytes.copy_from_slice(value);
185 MeshcopTlv::ActiveTimestamp(Timestamp(u64::from_le_bytes(bytes)))
186 }
187
188 OT_MESHCOP_TLV_PENDINGTIMESTAMP if value.len() == 8 => {
189 let mut bytes = [0u8; 8];
190 bytes.copy_from_slice(value);
191 MeshcopTlv::PendingTimestamp(Timestamp(u64::from_le_bytes(bytes)))
192 }
193
194 OT_MESHCOP_TLV_NETWORKNAME
195 | OT_MESHCOP_TLV_CHANNEL
196 | OT_MESHCOP_TLV_PANID
197 | OT_MESHCOP_TLV_DELAYTIMER
198 | OT_MESHCOP_TLV_ACTIVETIMESTAMP
199 | OT_MESHCOP_TLV_PENDINGTIMESTAMP => {
200 warn!("Unexpected TLV length {} for type {}", value.len(), tlv_type);
205 MeshcopTlv::Unknown(tlv_type, value)
206 }
207
208 _ => MeshcopTlv::Unknown(tlv_type, value),
209 }
210 }
211
212 fn parse_and_update(data: &'a [u8]) -> Result<(MeshcopTlv<'a>, &'a [u8]), ParseError> {
213 if data.len() < 2 {
214 return Err(ParseError);
215 }
216 let (value, ret) = if data[1] == TLV_ESCAPE_LENGTH {
217 if data.len() < 3 {
218 return Err(ParseError);
219 }
220
221 let len = u16::from_le_bytes([data[2], data[3]]) as usize;
222
223 if data.len() < 3 + len {
224 return Err(ParseError);
225 }
226
227 (&data[3..3 + len], &data[3 + len..])
228 } else {
229 let len = data[1] as usize;
230
231 if data.len() < 2 + len {
232 return Err(ParseError);
233 }
234
235 (&data[2..2 + len], &data[2 + len..])
236 };
237
238 Ok((MeshcopTlv::from_type_and_value(data[0], value), ret))
239 }
240}
241
242#[derive(Debug)]
244pub struct MeshcopTlvIterator<'a>(&'a [u8]);
245
246impl<'a> Iterator for MeshcopTlvIterator<'a> {
247 type Item = Result<MeshcopTlv<'a>, ParseError>;
248
249 fn next(&mut self) -> Option<Self::Item> {
250 if self.0.len() < 2 {
251 return None;
252 }
253 match MeshcopTlv::parse_and_update(self.0) {
254 Ok((tlv, data)) => {
255 self.0 = data;
256 Some(Ok(tlv))
257 }
258 Err(x) => Some(Err(x)),
259 }
260 }
261}
262
263pub trait TlvIteratorExt {
265 fn meshcop_tlvs(&self) -> MeshcopTlvIterator<'_>;
267}
268
269impl TlvIteratorExt for &[u8] {
270 fn meshcop_tlvs(&self) -> MeshcopTlvIterator<'_> {
271 MeshcopTlvIterator(self)
272 }
273}
274
275#[cfg(test)]
276mod test {
277 use super::*;
278
279 #[test]
280 fn test_tlv_deserialize_serialize() {
281 let data = hex::decode("0e080000000000010000000300000b35060004001fffc00208029c6f4dbae059cb0708fd0087d0e40b384405105f7ddf9e9e9670d81331ad06754660320308626c61686e6574320102f09f04105d95f609e1e842c47a69ddd77e23e23d0c0402a0fff8").unwrap();
282 let data = data.as_slice();
283
284 let tlvs =
285 data.meshcop_tlvs().collect::<Result<Vec<_>, _>>().expect("Failed to parse TLVs");
286
287 let mut data2 = vec![];
288
289 tlvs.into_iter().for_each(|x| x.write_to(&mut data2).unwrap());
290
291 assert_eq!(data, data2);
292 }
293}