dot15d4_frame/lib.rs
1//! Zero-copy read and write structures for handling IEEE 802.15.4 MAC frames.
2//!
3//! Each reader contains the following functions:
4//! - [`new`]: Create a new reader.
5//! - [`check_len`]: Check if the buffer is long enough to contain a valid
6//! frame.
7//! - [`new_unchecked`]: Create a new reader without checking the buffer length.
8//!
9//! The most important reader is the [`Frame`] reader, which is used to read a
10//! full IEEE 802.15.4 frame. The reader provides the following functions:
11//! - [`frame_control`]: returns a [`FrameControl`] reader.
12//! - [`sequence_number`]: returns the sequence number if not suppressed.
13//! - [`addressing`]: returns an [`AddressingFields`] reader.
14//! - [`auxiliary_security_header`]: returns an [`AuxiliarySecurityHeader`]
15//! reader.
16//! - [`information_elements`]: returns an [`InformationElements`] reader.
17//! - [`payload`]: returns the payload of the frame.
18//!
19//! ## Reading a frame
20//! For an incoming frame, use the [`Frame`] structure to read its content.
21//! ```
22//! # use dot15d4_frame::{
23//! # Frame,
24//! # FrameControl,
25//! # FrameType,
26//! # AddressingFields,
27//! # NestedInformationElementsIterator,
28//! # PayloadGroupId,
29//! # NestedSubId,
30//! # NestedSubIdShort,
31//! # TschTimeslot,
32//! # };
33//! # let frame: [u8; 35] = [
34//! # 0x40, 0xeb, 0xcd, 0xab, 0xff, 0xff, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
35//! # 0x00, 0x3f, 0x11, 0x88, 0x06, 0x1a, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x1c,
36//! # 0x00, 0x01, 0xc8, 0x00, 0x01, 0x1b, 0x00,
37//! # ];
38//! let frame = Frame::new(&frame).unwrap();
39//! let fc = frame.frame_control();
40//! let src_addr = frame.addressing().unwrap().src_address();
41//! let dst_addr = frame.addressing().unwrap().dst_address();
42//!
43//! assert_eq!(fc.frame_type(), FrameType::Beacon);
44//!
45//! let Some(ie) = frame.information_elements() else { return; };
46//!
47//! for payload in ie.payload_information_elements() {
48//! if matches!(payload.group_id(), PayloadGroupId::Mlme) {
49//! for nested in payload.nested_information_elements() {
50//! match nested.sub_id() {
51//! NestedSubId::Short(NestedSubIdShort::TschTimeslot) => {
52//! let time_slot = TschTimeslot::new(nested.content()).unwrap();
53//! assert_eq!(time_slot.id(), 0);
54//! }
55//! _ => (),
56//! }
57//! }
58//! }
59//! }
60//! ```
61//!
62//! ## Writing a frame
63//!
64//! __Work in progress!__
65//!
66//! ## Information Elements
67//!
68//! The IEEE 802.15.4 standard defines a set of Information Elements (IEs) that
69//! can be included in the frame. These IEs are used to provide additional
70//! information about the frame, such as timestamping, channel hopping, and
71//! more. The IEs are divided into two groups: Header IEs and Payload IEs.
72//! Calling [`information_elements`] on a [`Frame`] reader returns an
73//! [`InformationElements`] reader. The reader provides access to the Header and
74//! Payload IEs, via the [`header_information_elements`] and
75//! [`payload_information_elements`] functions.
76//!
77//! ### Header Information Elements
78//!
79//! The Header IEs are located in the frame header, and are used to provide
80//! information about the frame itself. The following IEs are defined in the
81//! standard:
82//!
83//! - [x] [`VendorSpecific`]
84//! - [x] [`Csl`]
85//! - [x] [`Rit`]
86//! - [ ] `DsmePanDescriptor`
87//! - [x] [`RendezvousTime`]
88//! - [x] [`TimeCorrection`]
89//! - [ ] `ExtededDsmePanDescriptor`
90//! - [ ] `FragmentSequencecontextDescription`
91//! - [x] [`SimplifiedSuperframeSpecification`]
92//! - [ ] `SimplifiedGtsSpecification`
93//! - [ ] `LecimCapabilities`
94//! - [ ] `TrleDescriptor`
95//! - [ ] `RccCapabilities`
96//! - [ ] `RccnDescriptor`
97//! - [ ] `GlobalTime`
98//! - [ ] `Da`
99//! - [x] [`HeaderTermination1`]
100//! - [x] [`HeaderTermination2`]
101//!
102//! ### Payload Information Elements
103//!
104//! The Payload IEs are located in the frame payload, and are used to provide
105//! information about the payload itself. The following IEs are defined in the
106//! standard:
107//!
108//! - [ ] `Esdu`
109//! - [x] `Mlme`: The MLME group contains a set of nested IEs. Call
110//! [`nested_information_elements`]
111//! to get an iterator over the nested IEs.
112//! - [ ] `VendorSpecific`
113//! - [ ] `PayloadTermination`
114//!
115//! ### Nested Information Elements
116//!
117//! Some IEs contain nested IEs. The [`NestedInformationElementsIterator`]
118//! provides an iterator over the nested IEs. The iterator is used to parse the
119//! nested IEs.
120//!
121//! The Nested IEs are split into two groups: Short and Long. The following
122//! short IEs are defined in the standard:
123//!
124//! - [x] [`TschSynchronization`]
125//! - [x] [`TschSlotframeAndLink`]
126//! - [x] [`TschTimeslot`]
127//! - [ ] `HoppingTiming`
128//! - [ ] `EnhancedBeaconFilter`
129//! - [ ] `MacMetrics`
130//! - [ ] `AllMacMetrics`
131//! - [ ] `CoexistenceSpecification`
132//! - [ ] `SunDeviceCapabilities`
133//! - [ ] `SunFskGenericPhy`
134//! - [ ] `ModeSwitchParameter`
135//! - [ ] `PhyParameterChange`
136//! - [ ] `OQpskPhyMode`
137//! - [ ] `PcaAllocation`
138//! - [ ] `LecimDsssOperatingMode`
139//! - [ ] `LecimFskOperatingMode`
140//! - [ ] `TvwsPhyOperatingMode`
141//! - [ ] `TvwsDeviceCapabilities`
142//! - [ ] `TvwsDeviceCategory`
143//! - [ ] `TvwsDeviceIdentification`
144//! - [ ] `TvwsDeviceLocation`
145//! - [ ] `TvwsChannelInformationQuery`
146//! - [ ] `TvwsChannelInformationSource`
147//! - [ ] `Ctm`
148//! - [ ] `Timestamp`
149//! - [ ] `TimestampDifference`
150//! - [ ] `TmctpSpecification`
151//! - [ ] `RccPhyOperatingMode`
152//! - [ ] `LinkMargin`
153//! - [ ] `RsGfskDeviceCapabilities`
154//! - [ ] `MultiPhy`
155//! - [ ] `VendorSpecific`
156//! - [ ] `Srm`
157//!
158//! The following long IEs are defined in the standard:
159//!
160//! - [ ] `VendorSpecificNested`
161//! - [x] [`ChannelHopping`]
162//!
163//! [`new`]: Frame::new
164//! [`check_len`]: Frame::check_len
165//! [`new_unchecked`]: Frame::new_unchecked
166//! [`frame_control`]: Frame::frame_control
167//! [`sequence_number`]: Frame::sequence_number
168//! [`addressing`]: Frame::addressing
169//! [`auxiliary_security_header`]: Frame::auxiliary_security_header
170//! [`information_elements`]: Frame::information_elements
171//! [`payload`]: Frame::payload
172//! [`HeaderTermination1`]: HeaderElementId::HeaderTermination1
173//! [`HeaderTermination2`]: HeaderElementId::HeaderTermination2
174//! [`header_information_elements`]: InformationElements::header_information_elements
175//! [`payload_information_elements`]: InformationElements::payload_information_elements
176//! [`nested_information_elements`]: PayloadInformationElement::nested_information_elements
177
178#![cfg_attr(not(any(test, feature = "std")), no_std)]
179#![deny(missing_docs)]
180#![deny(unsafe_code)]
181
182#[cfg(test)]
183mod tests;
184
185mod time;
186
187mod frame_control;
188pub use frame_control::*;
189
190mod aux_sec_header;
191pub use aux_sec_header::*;
192
193mod addressing;
194pub use addressing::*;
195
196mod ie;
197pub use ie::*;
198
199mod repr;
200pub use repr::*;
201
202/// An error that can occur when reading or writing an IEEE 802.15.4 frame.
203#[derive(Debug, Clone, Copy)]
204pub struct Error;
205
206/// A type alias for `Result<T, frame::Error>`.
207pub type Result<T> = core::result::Result<T, Error>;
208
209/// A reader/writer for an IEEE 802.15.4 frame.
210#[derive(Debug, Clone, Copy, PartialEq, Eq)]
211pub struct Frame<T: AsRef<[u8]>> {
212 buffer: T,
213}
214
215impl<T: AsRef<[u8]>> Frame<T> {
216 /// Create a new [`Frame`] reader/writer from a given buffer.
217 ///
218 /// # Errors
219 ///
220 /// Returns an error if the buffer is too short to contain a valid frame.
221 pub fn new(buffer: T) -> Result<Self> {
222 let b = Self::new_unchecked(buffer);
223
224 if !b.check_len() {
225 return Err(Error);
226 }
227
228 let fc = b.frame_control();
229
230 if fc.security_enabled() {
231 return Err(Error);
232 }
233
234 if fc.frame_type() == FrameType::Unknown {
235 return Err(Error);
236 }
237
238 if fc.frame_version() == FrameVersion::Unknown {
239 return Err(Error);
240 }
241
242 if fc.dst_addressing_mode() == AddressingMode::Unknown {
243 return Err(Error);
244 }
245
246 if fc.src_addressing_mode() == AddressingMode::Unknown {
247 return Err(Error);
248 }
249
250 Ok(b)
251 }
252
253 /// Returns `false` if the buffer is too short to contain a valid frame.
254 fn check_len(&self) -> bool {
255 let buffer = self.buffer.as_ref();
256
257 if buffer.len() < 2 || buffer.len() > 127 {
258 return false;
259 }
260
261 let fc = self.frame_control();
262
263 if !fc.sequence_number_suppression() && buffer.len() < 3 {
264 return false;
265 }
266
267 true
268 }
269
270 /// Create a new [`Frame`] reader/writer from a given buffer without length
271 /// checking.
272 pub fn new_unchecked(buffer: T) -> Self {
273 Self { buffer }
274 }
275
276 /// Return a [`FrameControl`] reader.
277 pub fn frame_control(&self) -> FrameControl<&'_ [u8]> {
278 FrameControl::new_unchecked(&self.buffer.as_ref()[..2])
279 }
280
281 /// Return the sequence number if not suppressed.
282 pub fn sequence_number(&self) -> Option<u8> {
283 if self.frame_control().sequence_number_suppression() {
284 None
285 } else {
286 Some(self.buffer.as_ref()[2])
287 }
288 }
289
290 /// Return an [`AddressingFields`] reader.
291 pub fn addressing(&self) -> Option<AddressingFields<&'_ [u8], &'_ [u8]>> {
292 let fc = self.frame_control();
293
294 if matches!(fc.frame_type(), FrameType::Ack)
295 && matches!(
296 fc.frame_version(),
297 FrameVersion::Ieee802154_2003 | FrameVersion::Ieee802154_2006
298 )
299 {
300 // Immediate Acks don't have addressing fields.
301 return None;
302 }
303
304 if fc.sequence_number_suppression() {
305 AddressingFields::new(&self.buffer.as_ref()[2..], fc).ok()
306 } else {
307 AddressingFields::new(&self.buffer.as_ref()[3..], fc).ok()
308 }
309 }
310
311 /// Return an [`AuxiliarySecurityHeader`] reader.
312 pub fn auxiliary_security_header(&self) -> Option<AuxiliarySecurityHeader<&'_ [u8]>> {
313 let fc = self.frame_control();
314
315 if fc.security_enabled() {
316 let mut offset = 2;
317
318 offset += !fc.sequence_number_suppression() as usize;
319
320 if let Some(af) = self.addressing() {
321 offset += af.len();
322 }
323
324 Some(AuxiliarySecurityHeader::new(
325 &self.buffer.as_ref()[offset..],
326 ))
327 } else {
328 None
329 }
330 }
331
332 /// Return an [`InformationElements`] reader.
333 pub fn information_elements(&self) -> Option<InformationElements<&'_ [u8]>> {
334 let fc = self.frame_control();
335 if fc.information_elements_present() {
336 let mut offset = 2;
337 offset += !fc.sequence_number_suppression() as usize;
338
339 if let Some(af) = self.addressing() {
340 offset += af.len();
341 }
342
343 Some(InformationElements::new(&self.buffer.as_ref()[offset..]).ok()?)
344 } else {
345 None
346 }
347 }
348}
349
350impl<'f, T: AsRef<[u8]> + ?Sized> Frame<&'f T> {
351 /// Return the payload of the frame.
352 pub fn payload(&self) -> Option<&'f [u8]> {
353 let fc = self.frame_control();
354
355 let mut offset = 0;
356 offset += 2;
357
358 if !fc.sequence_number_suppression() {
359 offset += 1;
360 }
361
362 if let Some(af) = self.addressing() {
363 offset += af.len();
364 }
365
366 if fc.security_enabled() {
367 offset += self.auxiliary_security_header().unwrap().len();
368 }
369
370 if fc.information_elements_present() {
371 if let Some(ie) = self.information_elements() {
372 offset += ie.len();
373 }
374 }
375
376 if self.buffer.as_ref().len() <= offset {
377 return None;
378 }
379
380 Some(&self.buffer.as_ref()[offset..])
381 }
382}
383
384impl<T: AsRef<[u8]> + AsMut<[u8]>> Frame<T> {
385 /// Set the Frame Control field values in the buffer, based on the given
386 /// [`FrameControlRepr`].
387 pub fn set_frame_control(&mut self, fc: &FrameControlRepr) {
388 let mut w = FrameControl::new_unchecked(&mut self.buffer.as_mut()[..2]);
389 w.set_frame_type(fc.frame_type);
390 w.set_security_enabled(fc.security_enabled);
391 w.set_frame_pending(fc.frame_pending);
392 w.set_ack_request(fc.ack_request);
393 w.set_pan_id_compression(fc.pan_id_compression);
394 w.set_sequence_number_suppression(fc.sequence_number_suppression);
395 w.set_information_elements_present(fc.information_elements_present);
396 w.set_dst_addressing_mode(fc.dst_addressing_mode);
397 w.set_src_addressing_mode(fc.src_addressing_mode);
398 w.set_frame_version(fc.frame_version);
399 }
400
401 /// Get a mutable reference to the Frame Control fields
402 pub fn frame_control_mut(&mut self) -> FrameControl<&'_ mut [u8]> {
403 FrameControl::new_unchecked(&mut self.buffer.as_mut()[..2])
404 }
405
406 /// Set the Sequence Number field value in the buffer.
407 pub fn set_sequence_number(&mut self, sequence_number: u8) {
408 // Set the sequence number suppression bit to false.
409 let mut w = FrameControl::new_unchecked(&mut self.buffer.as_mut()[..2]);
410 w.set_sequence_number_suppression(false);
411
412 self.buffer.as_mut()[2] = sequence_number;
413 }
414
415 /// Set the Addressing field values in the buffer, based on the given
416 /// [`AddressingFieldsRepr`].
417 pub fn set_addressing_fields(&mut self, addressing_fields: &AddressingFieldsRepr) {
418 let start = 2 + (!self.frame_control().sequence_number_suppression() as usize);
419
420 let (fc, addressing) = self.buffer.as_mut().split_at_mut(start);
421 let mut w = AddressingFields::new_unchecked(addressing, FrameControl::new_unchecked(fc));
422 w.write_fields(addressing_fields);
423 }
424
425 /// Set the Auxiliary Security Header field values in the buffer, based on
426 /// the given _.
427 pub fn set_aux_sec_header(&mut self) {
428 todo!();
429 }
430
431 /// Set the Information Elements field values in the buffer, based on the
432 /// given _.
433 pub fn set_information_elements(
434 &mut self,
435 ie: &InformationElementsRepr,
436 contains_payload: bool,
437 ) {
438 let mut offset = 2;
439 offset += !self.frame_control().sequence_number_suppression() as usize;
440
441 if let Some(af) = self.addressing() {
442 offset += af.len();
443 }
444
445 ie.emit(&mut self.buffer.as_mut()[offset..], contains_payload);
446 }
447
448 /// Set the payload of the frame.
449 pub fn set_payload(&mut self, payload: &[u8]) {
450 let mut offset = 0;
451 offset += 2;
452
453 if !self.frame_control().sequence_number_suppression() {
454 offset += 1;
455 }
456
457 if let Some(af) = self.addressing() {
458 offset += af.len();
459 }
460
461 if self.frame_control().security_enabled() {
462 offset += self.auxiliary_security_header().unwrap().len();
463 }
464
465 if self.frame_control().information_elements_present() {
466 offset += self.information_elements().unwrap().len();
467 }
468
469 self.buffer.as_mut()[offset..].copy_from_slice(payload);
470 }
471}
472
473impl<'f, T: AsRef<[u8]> + ?Sized> core::fmt::Display for Frame<&'f T> {
474 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
475 let fc = self.frame_control();
476 write!(f, "{}", fc)?;
477 if !fc.sequence_number_suppression() {
478 writeln!(f, "Sequence number: {}", self.sequence_number().unwrap())?;
479 }
480
481 if let Some(af) = self.addressing() {
482 write!(f, "{af}")?;
483 }
484
485 if fc.security_enabled() {
486 todo!();
487 }
488
489 if let Some(ie) = self.information_elements() {
490 writeln!(f, "Information Elements")?;
491 for header_ie in ie.header_information_elements() {
492 writeln!(f, " {}", header_ie)?;
493 }
494
495 for payload_ie in ie.payload_information_elements() {
496 writeln!(f, " {}", payload_ie)?;
497 }
498 }
499
500 if let Some(payload) = self.payload() {
501 writeln!(f, "Payload")?;
502 writeln!(f, " {:0x?}", payload)?;
503 }
504
505 Ok(())
506 }
507}