Skip to main content

stackforge_core/layer/dot15d4/
mod.rs

1//! IEEE 802.15.4 (Zigbee / Dot15d4) protocol layer implementation.
2//!
3//! Provides full 802.15.4 MAC frame parsing, building, and field access with:
4//! - Frame Control Field (FCF) with all flag/mode fields
5//! - Variable-length addressing (short and long addresses)
6//! - PAN ID compression support
7//! - Auxiliary Security Header (optional)
8//! - Beacon frames with superframe spec, GTS, and pending addresses
9//! - MAC command frames with all command payloads
10//! - FCS (CRC-16 CCITT Kermit) computation and verification
11//!
12//! All fields are little-endian as per the IEEE 802.15.4 standard.
13
14pub mod beacon;
15pub mod builder;
16pub mod command;
17pub mod crc;
18pub mod security;
19pub mod types;
20
21pub use builder::{Dot15d4Builder, Dot15d4FcsBuilder};
22
23use crate::layer::field::{
24    FieldError, FieldValue, read_u16_le, read_u64_le, write_u16_le, write_u64_le,
25};
26use crate::layer::{Layer, LayerIndex, LayerKind};
27
28/// Minimum header length: 2 bytes FCF + 1 byte sequence number.
29pub const DOT15D4_MIN_HEADER_LEN: usize = 3;
30
31/// FCS length in bytes (CRC-16).
32pub const FCS_LEN: usize = 2;
33
34/// Field names for dynamic access.
35pub const DOT15D4_FIELDS: &[&str] = &[
36    "fcf_frametype",
37    "fcf_security",
38    "fcf_pending",
39    "fcf_ackreq",
40    "fcf_panidcompress",
41    "fcf_destaddrmode",
42    "fcf_framever",
43    "fcf_srcaddrmode",
44    "seqnum",
45    "dest_panid",
46    "dest_addr_short",
47    "dest_addr_long",
48    "src_panid",
49    "src_addr_short",
50    "src_addr_long",
51];
52
53/// FCS layer field names (includes all base fields plus fcs).
54pub const DOT15D4_FCS_FIELDS: &[&str] = &[
55    "fcf_frametype",
56    "fcf_security",
57    "fcf_pending",
58    "fcf_ackreq",
59    "fcf_panidcompress",
60    "fcf_destaddrmode",
61    "fcf_framever",
62    "fcf_srcaddrmode",
63    "seqnum",
64    "dest_panid",
65    "dest_addr_short",
66    "dest_addr_long",
67    "src_panid",
68    "src_addr_short",
69    "src_addr_long",
70    "fcs",
71];
72
73// ============================================================================
74// Frame Control Field helpers
75// ============================================================================
76
77/// Read the 16-bit Frame Control Field (little-endian) from the buffer.
78#[inline]
79fn read_fcf(buf: &[u8], offset: usize) -> Result<u16, FieldError> {
80    read_u16_le(buf, offset)
81}
82
83/// Write the 16-bit Frame Control Field (little-endian) into the buffer.
84#[inline]
85fn write_fcf(buf: &mut [u8], offset: usize, fcf: u16) -> Result<(), FieldError> {
86    write_u16_le(fcf, buf, offset)
87}
88
89/// Extract frame type from FCF (bits 0-2).
90#[inline]
91#[must_use]
92pub fn fcf_frame_type(fcf: u16) -> u8 {
93    (fcf & 0x0007) as u8
94}
95
96/// Extract security enabled flag from FCF (bit 3).
97#[inline]
98#[must_use]
99pub fn fcf_security(fcf: u16) -> bool {
100    (fcf & 0x0008) != 0
101}
102
103/// Extract frame pending flag from FCF (bit 4).
104#[inline]
105#[must_use]
106pub fn fcf_pending(fcf: u16) -> bool {
107    (fcf & 0x0010) != 0
108}
109
110/// Extract ACK request flag from FCF (bit 5).
111#[inline]
112#[must_use]
113pub fn fcf_ackreq(fcf: u16) -> bool {
114    (fcf & 0x0020) != 0
115}
116
117/// Extract PAN ID compression flag from FCF (bit 6).
118#[inline]
119#[must_use]
120pub fn fcf_panid_compress(fcf: u16) -> bool {
121    (fcf & 0x0040) != 0
122}
123
124/// Extract destination address mode from FCF (bits 10-11).
125#[inline]
126#[must_use]
127pub fn fcf_dest_addr_mode(fcf: u16) -> u8 {
128    ((fcf >> 10) & 0x03) as u8
129}
130
131/// Extract frame version from FCF (bits 12-13).
132#[inline]
133#[must_use]
134pub fn fcf_frame_ver(fcf: u16) -> u8 {
135    ((fcf >> 12) & 0x03) as u8
136}
137
138/// Extract source address mode from FCF (bits 14-15).
139#[inline]
140#[must_use]
141pub fn fcf_src_addr_mode(fcf: u16) -> u8 {
142    ((fcf >> 14) & 0x03) as u8
143}
144
145/// Build a Frame Control Field value from individual fields.
146#[must_use]
147pub fn build_fcf(
148    frame_type: u8,
149    security: bool,
150    pending: bool,
151    ackreq: bool,
152    panid_compress: bool,
153    dest_addr_mode: u8,
154    frame_ver: u8,
155    src_addr_mode: u8,
156) -> u16 {
157    let mut fcf: u16 = 0;
158    fcf |= u16::from(frame_type) & 0x07;
159    if security {
160        fcf |= 0x0008;
161    }
162    if pending {
163        fcf |= 0x0010;
164    }
165    if ackreq {
166        fcf |= 0x0020;
167    }
168    if panid_compress {
169        fcf |= 0x0040;
170    }
171    // bits 7-9 reserved (0)
172    fcf |= (u16::from(dest_addr_mode) & 0x03) << 10;
173    fcf |= (u16::from(frame_ver) & 0x03) << 12;
174    fcf |= (u16::from(src_addr_mode) & 0x03) << 14;
175    fcf
176}
177
178/// Compute the variable header length based on FCF fields.
179///
180/// The header consists of:
181/// - 2 bytes FCF
182/// - 1 byte sequence number
183/// - Dest PAN ID (2 bytes if `dest_addr_mode` != 0)
184/// - Dest Address (2 or 8 bytes based on `dest_addr_mode`)
185/// - Src PAN ID (2 bytes if `src_addr_mode` != 0 AND NOT `panid_compress`)
186/// - Src Address (2 or 8 bytes based on `src_addr_mode`)
187#[must_use]
188pub fn compute_header_len(fcf: u16) -> usize {
189    let mut len = DOT15D4_MIN_HEADER_LEN; // FCF (2) + seqnum (1)
190    let dest_mode = fcf_dest_addr_mode(fcf);
191    let src_mode = fcf_src_addr_mode(fcf);
192    let panid_compress = fcf_panid_compress(fcf);
193
194    // Destination PAN ID + Address
195    if dest_mode != types::addr_mode::NONE {
196        len += 2; // PAN ID
197        len += types::addr_mode_len(dest_mode);
198    }
199
200    // Source PAN ID + Address
201    if src_mode != types::addr_mode::NONE {
202        if !panid_compress {
203            len += 2; // PAN ID (not compressed)
204        }
205        len += types::addr_mode_len(src_mode);
206    }
207
208    len
209}
210
211/// Compute the offset where addressing fields begin (after FCF + seqnum).
212#[inline]
213fn addr_start(start: usize) -> usize {
214    start + DOT15D4_MIN_HEADER_LEN
215}
216
217// ============================================================================
218// Dot15d4Layer -- zero-copy view into an 802.15.4 MAC frame
219// ============================================================================
220
221/// IEEE 802.15.4 MAC frame layer (without FCS).
222///
223/// This is a zero-copy view into the packet buffer. The header length
224/// is variable depending on the address modes specified in the FCF.
225#[derive(Debug, Clone)]
226pub struct Dot15d4Layer {
227    pub index: LayerIndex,
228}
229
230impl Dot15d4Layer {
231    /// Create a new `Dot15d4Layer` from start/end offsets.
232    #[must_use]
233    pub fn new(start: usize, end: usize) -> Self {
234        Self {
235            index: LayerIndex::new(LayerKind::Dot15d4, start, end),
236        }
237    }
238
239    /// Validate that the buffer has enough bytes for at least the minimum header.
240    pub fn validate(buf: &[u8], offset: usize) -> Result<(), FieldError> {
241        if buf.len() < offset + DOT15D4_MIN_HEADER_LEN {
242            return Err(FieldError::BufferTooShort {
243                offset,
244                need: DOT15D4_MIN_HEADER_LEN,
245                have: buf.len().saturating_sub(offset),
246            });
247        }
248        Ok(())
249    }
250
251    // ========================================================================
252    // Frame Control Field accessors
253    // ========================================================================
254
255    /// Read the raw 16-bit Frame Control Field.
256    #[inline]
257    pub fn fcf_raw(&self, buf: &[u8]) -> Result<u16, FieldError> {
258        read_fcf(buf, self.index.start)
259    }
260
261    /// Frame type (3 bits): 0=Beacon, 1=Data, 2=Ack, 3=Command.
262    pub fn fcf_frametype(&self, buf: &[u8]) -> Result<u8, FieldError> {
263        self.fcf_raw(buf).map(fcf_frame_type)
264    }
265
266    /// Security Enabled flag.
267    pub fn fcf_security(&self, buf: &[u8]) -> Result<bool, FieldError> {
268        self.fcf_raw(buf).map(fcf_security)
269    }
270
271    /// Frame Pending flag.
272    pub fn fcf_pending(&self, buf: &[u8]) -> Result<bool, FieldError> {
273        self.fcf_raw(buf).map(fcf_pending)
274    }
275
276    /// ACK Request flag.
277    pub fn fcf_ackreq(&self, buf: &[u8]) -> Result<bool, FieldError> {
278        self.fcf_raw(buf).map(fcf_ackreq)
279    }
280
281    /// PAN ID Compression flag (intra-PAN).
282    pub fn fcf_panidcompress(&self, buf: &[u8]) -> Result<bool, FieldError> {
283        self.fcf_raw(buf).map(fcf_panid_compress)
284    }
285
286    /// Destination Address Mode (2 bits): 0=None, 2=Short, 3=Long.
287    pub fn fcf_destaddrmode(&self, buf: &[u8]) -> Result<u8, FieldError> {
288        self.fcf_raw(buf).map(fcf_dest_addr_mode)
289    }
290
291    /// Frame Version (2 bits).
292    pub fn fcf_framever(&self, buf: &[u8]) -> Result<u8, FieldError> {
293        self.fcf_raw(buf).map(fcf_frame_ver)
294    }
295
296    /// Source Address Mode (2 bits): 0=None, 2=Short, 3=Long.
297    pub fn fcf_srcaddrmode(&self, buf: &[u8]) -> Result<u8, FieldError> {
298        self.fcf_raw(buf).map(fcf_src_addr_mode)
299    }
300
301    // ========================================================================
302    // Sequence Number
303    // ========================================================================
304
305    /// Sequence number (1 byte).
306    pub fn seqnum(&self, buf: &[u8]) -> Result<u8, FieldError> {
307        let off = self.index.start + 2;
308        if buf.len() <= off {
309            return Err(FieldError::BufferTooShort {
310                offset: off,
311                need: 1,
312                have: buf.len().saturating_sub(off),
313            });
314        }
315        Ok(buf[off])
316    }
317
318    /// Set sequence number.
319    pub fn set_seqnum(&self, buf: &mut [u8], val: u8) -> Result<(), FieldError> {
320        let off = self.index.start + 2;
321        if buf.len() <= off {
322            return Err(FieldError::BufferTooShort {
323                offset: off,
324                need: 1,
325                have: buf.len().saturating_sub(off),
326            });
327        }
328        buf[off] = val;
329        Ok(())
330    }
331
332    // ========================================================================
333    // Addressing field offsets (computed from FCF)
334    // ========================================================================
335
336    /// Compute the offset of the destination PAN ID field.
337    /// Returns None if `dest_addr_mode` == 0.
338    fn dest_panid_offset(&self, buf: &[u8]) -> Result<Option<usize>, FieldError> {
339        let fcf = self.fcf_raw(buf)?;
340        let dest_mode = fcf_dest_addr_mode(fcf);
341        if dest_mode == types::addr_mode::NONE {
342            return Ok(None);
343        }
344        Ok(Some(addr_start(self.index.start)))
345    }
346
347    /// Compute the offset of the destination address field.
348    /// Returns None if `dest_addr_mode` == 0.
349    fn dest_addr_offset(&self, buf: &[u8]) -> Result<Option<usize>, FieldError> {
350        let fcf = self.fcf_raw(buf)?;
351        let dest_mode = fcf_dest_addr_mode(fcf);
352        if dest_mode == types::addr_mode::NONE {
353            return Ok(None);
354        }
355        // After dest PAN ID (2 bytes)
356        Ok(Some(addr_start(self.index.start) + 2))
357    }
358
359    /// Compute the offset of the source PAN ID field.
360    /// Returns None if `src_addr_mode` == 0 or PAN ID compressed.
361    fn src_panid_offset(&self, buf: &[u8]) -> Result<Option<usize>, FieldError> {
362        let fcf = self.fcf_raw(buf)?;
363        let dest_mode = fcf_dest_addr_mode(fcf);
364        let src_mode = fcf_src_addr_mode(fcf);
365        let panid_compress = fcf_panid_compress(fcf);
366
367        if src_mode == types::addr_mode::NONE || panid_compress {
368            return Ok(None);
369        }
370
371        let mut off = addr_start(self.index.start);
372        if dest_mode != types::addr_mode::NONE {
373            off += 2 + types::addr_mode_len(dest_mode); // PAN ID + address
374        }
375        Ok(Some(off))
376    }
377
378    /// Compute the offset of the source address field.
379    /// Returns None if `src_addr_mode` == 0.
380    fn src_addr_offset(&self, buf: &[u8]) -> Result<Option<usize>, FieldError> {
381        let fcf = self.fcf_raw(buf)?;
382        let dest_mode = fcf_dest_addr_mode(fcf);
383        let src_mode = fcf_src_addr_mode(fcf);
384        let panid_compress = fcf_panid_compress(fcf);
385
386        if src_mode == types::addr_mode::NONE {
387            return Ok(None);
388        }
389
390        let mut off = addr_start(self.index.start);
391        // Skip dest PAN ID + dest addr
392        if dest_mode != types::addr_mode::NONE {
393            off += 2 + types::addr_mode_len(dest_mode);
394        }
395        // Skip src PAN ID if present
396        if !panid_compress {
397            off += 2;
398        }
399        Ok(Some(off))
400    }
401
402    // ========================================================================
403    // Addressing field readers
404    // ========================================================================
405
406    /// Destination PAN ID (2 bytes, LE).
407    /// Returns None if `dest_addr_mode` == 0.
408    pub fn dest_panid(&self, buf: &[u8]) -> Result<Option<u16>, FieldError> {
409        match self.dest_panid_offset(buf)? {
410            Some(off) => read_u16_le(buf, off).map(Some),
411            None => Ok(None),
412        }
413    }
414
415    /// Destination short address (2 bytes, LE).
416    /// Returns None if `dest_addr_mode` != SHORT.
417    pub fn dest_addr_short(&self, buf: &[u8]) -> Result<Option<u16>, FieldError> {
418        let fcf = self.fcf_raw(buf)?;
419        if fcf_dest_addr_mode(fcf) != types::addr_mode::SHORT {
420            return Ok(None);
421        }
422        match self.dest_addr_offset(buf)? {
423            Some(off) => read_u16_le(buf, off).map(Some),
424            None => Ok(None),
425        }
426    }
427
428    /// Destination long address (8 bytes, LE).
429    /// Returns None if `dest_addr_mode` != LONG.
430    pub fn dest_addr_long(&self, buf: &[u8]) -> Result<Option<u64>, FieldError> {
431        let fcf = self.fcf_raw(buf)?;
432        if fcf_dest_addr_mode(fcf) != types::addr_mode::LONG {
433            return Ok(None);
434        }
435        match self.dest_addr_offset(buf)? {
436            Some(off) => read_u64_le(buf, off).map(Some),
437            None => Ok(None),
438        }
439    }
440
441    /// Source PAN ID (2 bytes, LE).
442    /// Returns None if `src_addr_mode` == 0 or PAN ID compressed.
443    pub fn src_panid(&self, buf: &[u8]) -> Result<Option<u16>, FieldError> {
444        match self.src_panid_offset(buf)? {
445            Some(off) => read_u16_le(buf, off).map(Some),
446            None => Ok(None),
447        }
448    }
449
450    /// Source short address (2 bytes, LE).
451    /// Returns None if `src_addr_mode` != SHORT.
452    pub fn src_addr_short(&self, buf: &[u8]) -> Result<Option<u16>, FieldError> {
453        let fcf = self.fcf_raw(buf)?;
454        if fcf_src_addr_mode(fcf) != types::addr_mode::SHORT {
455            return Ok(None);
456        }
457        match self.src_addr_offset(buf)? {
458            Some(off) => read_u16_le(buf, off).map(Some),
459            None => Ok(None),
460        }
461    }
462
463    /// Source long address (8 bytes, LE).
464    /// Returns None if `src_addr_mode` != LONG.
465    pub fn src_addr_long(&self, buf: &[u8]) -> Result<Option<u64>, FieldError> {
466        let fcf = self.fcf_raw(buf)?;
467        if fcf_src_addr_mode(fcf) != types::addr_mode::LONG {
468            return Ok(None);
469        }
470        match self.src_addr_offset(buf)? {
471            Some(off) => read_u64_le(buf, off).map(Some),
472            None => Ok(None),
473        }
474    }
475
476    // ========================================================================
477    // FCF field writers
478    // ========================================================================
479
480    /// Set the frame type in the FCF.
481    pub fn set_fcf_frametype(&self, buf: &mut [u8], val: u8) -> Result<(), FieldError> {
482        let mut fcf = self.fcf_raw(buf)?;
483        fcf = (fcf & !0x0007) | (u16::from(val) & 0x07);
484        write_fcf(buf, self.index.start, fcf)
485    }
486
487    /// Set the security enabled flag in the FCF.
488    pub fn set_fcf_security(&self, buf: &mut [u8], val: bool) -> Result<(), FieldError> {
489        let mut fcf = self.fcf_raw(buf)?;
490        if val {
491            fcf |= 0x0008;
492        } else {
493            fcf &= !0x0008;
494        }
495        write_fcf(buf, self.index.start, fcf)
496    }
497
498    /// Set the frame pending flag in the FCF.
499    pub fn set_fcf_pending(&self, buf: &mut [u8], val: bool) -> Result<(), FieldError> {
500        let mut fcf = self.fcf_raw(buf)?;
501        if val {
502            fcf |= 0x0010;
503        } else {
504            fcf &= !0x0010;
505        }
506        write_fcf(buf, self.index.start, fcf)
507    }
508
509    /// Set the ACK request flag in the FCF.
510    pub fn set_fcf_ackreq(&self, buf: &mut [u8], val: bool) -> Result<(), FieldError> {
511        let mut fcf = self.fcf_raw(buf)?;
512        if val {
513            fcf |= 0x0020;
514        } else {
515            fcf &= !0x0020;
516        }
517        write_fcf(buf, self.index.start, fcf)
518    }
519
520    /// Set the PAN ID compression flag in the FCF.
521    pub fn set_fcf_panidcompress(&self, buf: &mut [u8], val: bool) -> Result<(), FieldError> {
522        let mut fcf = self.fcf_raw(buf)?;
523        if val {
524            fcf |= 0x0040;
525        } else {
526            fcf &= !0x0040;
527        }
528        write_fcf(buf, self.index.start, fcf)
529    }
530
531    /// Set the destination address mode in the FCF.
532    pub fn set_fcf_destaddrmode(&self, buf: &mut [u8], val: u8) -> Result<(), FieldError> {
533        let mut fcf = self.fcf_raw(buf)?;
534        fcf = (fcf & !0x0C00) | ((u16::from(val) & 0x03) << 10);
535        write_fcf(buf, self.index.start, fcf)
536    }
537
538    /// Set the frame version in the FCF.
539    pub fn set_fcf_framever(&self, buf: &mut [u8], val: u8) -> Result<(), FieldError> {
540        let mut fcf = self.fcf_raw(buf)?;
541        fcf = (fcf & !0x3000) | ((u16::from(val) & 0x03) << 12);
542        write_fcf(buf, self.index.start, fcf)
543    }
544
545    /// Set the source address mode in the FCF.
546    pub fn set_fcf_srcaddrmode(&self, buf: &mut [u8], val: u8) -> Result<(), FieldError> {
547        let mut fcf = self.fcf_raw(buf)?;
548        fcf = (fcf & !0xC000) | ((u16::from(val) & 0x03) << 14);
549        write_fcf(buf, self.index.start, fcf)
550    }
551
552    // ========================================================================
553    // Addressing field writers
554    // ========================================================================
555
556    /// Set the destination PAN ID.
557    pub fn set_dest_panid(&self, buf: &mut [u8], val: u16) -> Result<(), FieldError> {
558        match self.dest_panid_offset(buf)? {
559            Some(off) => write_u16_le(val, buf, off),
560            None => Err(FieldError::InvalidValue(
561                "dest_addr_mode is None, cannot set dest_panid".into(),
562            )),
563        }
564    }
565
566    /// Set the destination short address.
567    pub fn set_dest_addr_short(&self, buf: &mut [u8], val: u16) -> Result<(), FieldError> {
568        let fcf = self.fcf_raw(buf)?;
569        if fcf_dest_addr_mode(fcf) != types::addr_mode::SHORT {
570            return Err(FieldError::InvalidValue(
571                "dest_addr_mode is not SHORT".into(),
572            ));
573        }
574        match self.dest_addr_offset(buf)? {
575            Some(off) => write_u16_le(val, buf, off),
576            None => Err(FieldError::InvalidValue("no dest address offset".into())),
577        }
578    }
579
580    /// Set the destination long address.
581    pub fn set_dest_addr_long(&self, buf: &mut [u8], val: u64) -> Result<(), FieldError> {
582        let fcf = self.fcf_raw(buf)?;
583        if fcf_dest_addr_mode(fcf) != types::addr_mode::LONG {
584            return Err(FieldError::InvalidValue(
585                "dest_addr_mode is not LONG".into(),
586            ));
587        }
588        match self.dest_addr_offset(buf)? {
589            Some(off) => write_u64_le(val, buf, off),
590            None => Err(FieldError::InvalidValue("no dest address offset".into())),
591        }
592    }
593
594    /// Set the source PAN ID.
595    pub fn set_src_panid(&self, buf: &mut [u8], val: u16) -> Result<(), FieldError> {
596        match self.src_panid_offset(buf)? {
597            Some(off) => write_u16_le(val, buf, off),
598            None => Err(FieldError::InvalidValue(
599                "src PAN ID not present (compressed or src_addr_mode is None)".into(),
600            )),
601        }
602    }
603
604    /// Set the source short address.
605    pub fn set_src_addr_short(&self, buf: &mut [u8], val: u16) -> Result<(), FieldError> {
606        let fcf = self.fcf_raw(buf)?;
607        if fcf_src_addr_mode(fcf) != types::addr_mode::SHORT {
608            return Err(FieldError::InvalidValue(
609                "src_addr_mode is not SHORT".into(),
610            ));
611        }
612        match self.src_addr_offset(buf)? {
613            Some(off) => write_u16_le(val, buf, off),
614            None => Err(FieldError::InvalidValue("no src address offset".into())),
615        }
616    }
617
618    /// Set the source long address.
619    pub fn set_src_addr_long(&self, buf: &mut [u8], val: u64) -> Result<(), FieldError> {
620        let fcf = self.fcf_raw(buf)?;
621        if fcf_src_addr_mode(fcf) != types::addr_mode::LONG {
622            return Err(FieldError::InvalidValue("src_addr_mode is not LONG".into()));
623        }
624        match self.src_addr_offset(buf)? {
625            Some(off) => write_u64_le(val, buf, off),
626            None => Err(FieldError::InvalidValue("no src address offset".into())),
627        }
628    }
629
630    // ========================================================================
631    // Dynamic field access
632    // ========================================================================
633
634    /// Get a field value by name.
635    pub fn get_field(&self, buf: &[u8], name: &str) -> Option<Result<FieldValue, FieldError>> {
636        match name {
637            "fcf_frametype" => Some(self.fcf_frametype(buf).map(FieldValue::U8)),
638            "fcf_security" => Some(self.fcf_security(buf).map(FieldValue::Bool)),
639            "fcf_pending" => Some(self.fcf_pending(buf).map(FieldValue::Bool)),
640            "fcf_ackreq" => Some(self.fcf_ackreq(buf).map(FieldValue::Bool)),
641            "fcf_panidcompress" => Some(self.fcf_panidcompress(buf).map(FieldValue::Bool)),
642            "fcf_destaddrmode" => Some(self.fcf_destaddrmode(buf).map(FieldValue::U8)),
643            "fcf_framever" => Some(self.fcf_framever(buf).map(FieldValue::U8)),
644            "fcf_srcaddrmode" => Some(self.fcf_srcaddrmode(buf).map(FieldValue::U8)),
645            "seqnum" => Some(self.seqnum(buf).map(FieldValue::U8)),
646            "dest_panid" => Some(
647                self.dest_panid(buf)
648                    .map(|opt| opt.map_or(FieldValue::U16(0), FieldValue::U16)),
649            ),
650            "dest_addr_short" => Some(
651                self.dest_addr_short(buf)
652                    .map(|opt| opt.map_or(FieldValue::U16(0), FieldValue::U16)),
653            ),
654            "dest_addr_long" => Some(
655                self.dest_addr_long(buf)
656                    .map(|opt| opt.map_or(FieldValue::U64(0), FieldValue::U64)),
657            ),
658            "src_panid" => Some(
659                self.src_panid(buf)
660                    .map(|opt| opt.map_or(FieldValue::U16(0), FieldValue::U16)),
661            ),
662            "src_addr_short" => Some(
663                self.src_addr_short(buf)
664                    .map(|opt| opt.map_or(FieldValue::U16(0), FieldValue::U16)),
665            ),
666            "src_addr_long" => Some(
667                self.src_addr_long(buf)
668                    .map(|opt| opt.map_or(FieldValue::U64(0), FieldValue::U64)),
669            ),
670            _ => None,
671        }
672    }
673
674    /// Set a field value by name.
675    pub fn set_field(
676        &self,
677        buf: &mut [u8],
678        name: &str,
679        value: FieldValue,
680    ) -> Option<Result<(), FieldError>> {
681        match name {
682            "fcf_frametype" => Some(match value.as_u8() {
683                Some(v) => self.set_fcf_frametype(buf, v),
684                None => Err(FieldError::InvalidValue(
685                    "expected u8 for fcf_frametype".into(),
686                )),
687            }),
688            "fcf_security" => Some(match value.as_bool() {
689                Some(v) => self.set_fcf_security(buf, v),
690                None => Err(FieldError::InvalidValue(
691                    "expected bool for fcf_security".into(),
692                )),
693            }),
694            "fcf_pending" => Some(match value.as_bool() {
695                Some(v) => self.set_fcf_pending(buf, v),
696                None => Err(FieldError::InvalidValue(
697                    "expected bool for fcf_pending".into(),
698                )),
699            }),
700            "fcf_ackreq" => Some(match value.as_bool() {
701                Some(v) => self.set_fcf_ackreq(buf, v),
702                None => Err(FieldError::InvalidValue(
703                    "expected bool for fcf_ackreq".into(),
704                )),
705            }),
706            "fcf_panidcompress" => Some(match value.as_bool() {
707                Some(v) => self.set_fcf_panidcompress(buf, v),
708                None => Err(FieldError::InvalidValue(
709                    "expected bool for fcf_panidcompress".into(),
710                )),
711            }),
712            "fcf_destaddrmode" => Some(match value.as_u8() {
713                Some(v) => self.set_fcf_destaddrmode(buf, v),
714                None => Err(FieldError::InvalidValue(
715                    "expected u8 for fcf_destaddrmode".into(),
716                )),
717            }),
718            "fcf_framever" => Some(match value.as_u8() {
719                Some(v) => self.set_fcf_framever(buf, v),
720                None => Err(FieldError::InvalidValue(
721                    "expected u8 for fcf_framever".into(),
722                )),
723            }),
724            "fcf_srcaddrmode" => Some(match value.as_u8() {
725                Some(v) => self.set_fcf_srcaddrmode(buf, v),
726                None => Err(FieldError::InvalidValue(
727                    "expected u8 for fcf_srcaddrmode".into(),
728                )),
729            }),
730            "seqnum" => Some(match value.as_u8() {
731                Some(v) => self.set_seqnum(buf, v),
732                None => Err(FieldError::InvalidValue("expected u8 for seqnum".into())),
733            }),
734            "dest_panid" => Some(match value.as_u16() {
735                Some(v) => self.set_dest_panid(buf, v),
736                None => Err(FieldError::InvalidValue(
737                    "expected u16 for dest_panid".into(),
738                )),
739            }),
740            "dest_addr_short" => Some(match value.as_u16() {
741                Some(v) => self.set_dest_addr_short(buf, v),
742                None => Err(FieldError::InvalidValue(
743                    "expected u16 for dest_addr_short".into(),
744                )),
745            }),
746            "dest_addr_long" => Some(match value.as_u64() {
747                Some(v) => self.set_dest_addr_long(buf, v),
748                None => Err(FieldError::InvalidValue(
749                    "expected u64 for dest_addr_long".into(),
750                )),
751            }),
752            "src_panid" => Some(match value.as_u16() {
753                Some(v) => self.set_src_panid(buf, v),
754                None => Err(FieldError::InvalidValue(
755                    "expected u16 for src_panid".into(),
756                )),
757            }),
758            "src_addr_short" => Some(match value.as_u16() {
759                Some(v) => self.set_src_addr_short(buf, v),
760                None => Err(FieldError::InvalidValue(
761                    "expected u16 for src_addr_short".into(),
762                )),
763            }),
764            "src_addr_long" => Some(match value.as_u64() {
765                Some(v) => self.set_src_addr_long(buf, v),
766                None => Err(FieldError::InvalidValue(
767                    "expected u64 for src_addr_long".into(),
768                )),
769            }),
770            _ => None,
771        }
772    }
773
774    /// Get the list of field names.
775    #[must_use]
776    pub fn field_names() -> &'static [&'static str] {
777        DOT15D4_FIELDS
778    }
779
780    /// Determine the next layer kind based on frame type.
781    #[must_use]
782    pub fn next_layer(&self, buf: &[u8]) -> Option<LayerKind> {
783        self.fcf_frametype(buf).ok().and_then(|ft| match ft {
784            types::frame_type::BEACON => None,
785            types::frame_type::DATA => Some(LayerKind::Raw),
786            types::frame_type::ACK => None,
787            types::frame_type::MAC_CMD => None,
788            _ => Some(LayerKind::Raw),
789        })
790    }
791
792    /// Format a long address as a colon-separated hex string.
793    #[must_use]
794    pub fn format_long_addr(addr: u64) -> String {
795        let bytes = addr.to_be_bytes();
796        format!(
797            "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
798            bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7]
799        )
800    }
801
802    /// Compute hash for packet matching (based on sequence number).
803    #[must_use]
804    pub fn hashret(&self, buf: &[u8]) -> Vec<u8> {
805        self.seqnum(buf).map(|s| vec![s]).unwrap_or_default()
806    }
807}
808
809impl Layer for Dot15d4Layer {
810    fn kind(&self) -> LayerKind {
811        LayerKind::Dot15d4
812    }
813
814    fn summary(&self, buf: &[u8]) -> String {
815        let ft = self.fcf_frametype(buf).unwrap_or(0);
816        let ackreq = self.fcf_ackreq(buf).unwrap_or(false);
817        let dest_mode = self.fcf_destaddrmode(buf).unwrap_or(0);
818        let src_mode = self.fcf_srcaddrmode(buf).unwrap_or(0);
819        let seq = self.seqnum(buf).unwrap_or(0);
820
821        format!(
822            "802.15.4 {} ackreq({}) ( {} -> {} ) Seq#{}",
823            types::frame_type_name(ft),
824            ackreq,
825            types::addr_mode_name(dest_mode),
826            types::addr_mode_name(src_mode),
827            seq,
828        )
829    }
830
831    fn header_len(&self, buf: &[u8]) -> usize {
832        match self.fcf_raw(buf) {
833            Ok(fcf) => {
834                let computed = compute_header_len(fcf);
835                let available = self.index.len();
836                computed.min(available)
837            },
838            Err(_) => DOT15D4_MIN_HEADER_LEN.min(self.index.len()),
839        }
840    }
841
842    fn hashret(&self, buf: &[u8]) -> Vec<u8> {
843        self.hashret(buf)
844    }
845
846    fn answers(&self, buf: &[u8], other: &Self, other_buf: &[u8]) -> bool {
847        // An ACK frame answers a frame if:
848        // 1. This is an ACK (frametype == 2)
849        // 2. Sequence numbers match
850        // 3. The other frame requested an ACK
851        if let (Ok(ft), Ok(seq), Ok(other_seq), Ok(other_ackreq)) = (
852            self.fcf_frametype(buf),
853            self.seqnum(buf),
854            other.seqnum(other_buf),
855            other.fcf_ackreq(other_buf),
856        ) && ft == types::frame_type::ACK
857            && seq == other_seq
858            && other_ackreq
859        {
860            return true;
861        }
862        false
863    }
864
865    fn field_names(&self) -> &'static [&'static str] {
866        DOT15D4_FIELDS
867    }
868}
869
870// ============================================================================
871// Dot15d4FcsLayer -- 802.15.4 frame with FCS
872// ============================================================================
873
874/// IEEE 802.15.4 MAC frame with FCS (2-byte CRC at the end).
875///
876/// This is a drop-in replacement for `Dot15d4Layer` that expects a
877/// 2-byte FCS/checksum at the end of the frame, and produces one
878/// when building.
879#[derive(Debug, Clone)]
880pub struct Dot15d4FcsLayer {
881    pub index: LayerIndex,
882}
883
884impl Dot15d4FcsLayer {
885    /// Create a new `Dot15d4FcsLayer` from start/end offsets.
886    #[must_use]
887    pub fn new(start: usize, end: usize) -> Self {
888        Self {
889            index: LayerIndex::new(LayerKind::Dot15d4Fcs, start, end),
890        }
891    }
892
893    /// Create the inner `Dot15d4Layer` view (excluding FCS bytes).
894    fn inner(&self) -> Dot15d4Layer {
895        Dot15d4Layer::new(self.index.start, self.index.end.saturating_sub(FCS_LEN))
896    }
897
898    /// Read the FCS value (2 bytes, LE) from the end of the frame.
899    pub fn fcs(&self, buf: &[u8]) -> Result<u16, FieldError> {
900        let slice = self.index.slice(buf);
901        if slice.len() < FCS_LEN {
902            return Err(FieldError::BufferTooShort {
903                offset: self.index.end.saturating_sub(FCS_LEN),
904                need: FCS_LEN,
905                have: slice.len(),
906            });
907        }
908        let fcs_offset = slice.len() - FCS_LEN;
909        Ok(u16::from_le_bytes([
910            slice[fcs_offset],
911            slice[fcs_offset + 1],
912        ]))
913    }
914
915    /// Verify the FCS of this frame.
916    pub fn verify_fcs(&self, buf: &[u8]) -> Result<bool, FieldError> {
917        let slice = self.index.slice(buf);
918        if slice.len() < FCS_LEN + DOT15D4_MIN_HEADER_LEN {
919            return Err(FieldError::BufferTooShort {
920                offset: self.index.start,
921                need: DOT15D4_MIN_HEADER_LEN + FCS_LEN,
922                have: slice.len(),
923            });
924        }
925        let data = &slice[..slice.len() - FCS_LEN];
926        let expected = self.fcs(buf)?;
927        Ok(crc::verify_fcs(data, expected))
928    }
929
930    // Delegate all FCF/addressing accessors to the inner layer.
931
932    pub fn fcf_raw(&self, buf: &[u8]) -> Result<u16, FieldError> {
933        self.inner().fcf_raw(buf)
934    }
935
936    pub fn fcf_frametype(&self, buf: &[u8]) -> Result<u8, FieldError> {
937        self.inner().fcf_frametype(buf)
938    }
939
940    pub fn fcf_security(&self, buf: &[u8]) -> Result<bool, FieldError> {
941        self.inner().fcf_security(buf)
942    }
943
944    pub fn fcf_pending(&self, buf: &[u8]) -> Result<bool, FieldError> {
945        self.inner().fcf_pending(buf)
946    }
947
948    pub fn fcf_ackreq(&self, buf: &[u8]) -> Result<bool, FieldError> {
949        self.inner().fcf_ackreq(buf)
950    }
951
952    pub fn fcf_panidcompress(&self, buf: &[u8]) -> Result<bool, FieldError> {
953        self.inner().fcf_panidcompress(buf)
954    }
955
956    pub fn fcf_destaddrmode(&self, buf: &[u8]) -> Result<u8, FieldError> {
957        self.inner().fcf_destaddrmode(buf)
958    }
959
960    pub fn fcf_framever(&self, buf: &[u8]) -> Result<u8, FieldError> {
961        self.inner().fcf_framever(buf)
962    }
963
964    pub fn fcf_srcaddrmode(&self, buf: &[u8]) -> Result<u8, FieldError> {
965        self.inner().fcf_srcaddrmode(buf)
966    }
967
968    pub fn seqnum(&self, buf: &[u8]) -> Result<u8, FieldError> {
969        self.inner().seqnum(buf)
970    }
971
972    pub fn dest_panid(&self, buf: &[u8]) -> Result<Option<u16>, FieldError> {
973        self.inner().dest_panid(buf)
974    }
975
976    pub fn dest_addr_short(&self, buf: &[u8]) -> Result<Option<u16>, FieldError> {
977        self.inner().dest_addr_short(buf)
978    }
979
980    pub fn dest_addr_long(&self, buf: &[u8]) -> Result<Option<u64>, FieldError> {
981        self.inner().dest_addr_long(buf)
982    }
983
984    pub fn src_panid(&self, buf: &[u8]) -> Result<Option<u16>, FieldError> {
985        self.inner().src_panid(buf)
986    }
987
988    pub fn src_addr_short(&self, buf: &[u8]) -> Result<Option<u16>, FieldError> {
989        self.inner().src_addr_short(buf)
990    }
991
992    pub fn src_addr_long(&self, buf: &[u8]) -> Result<Option<u64>, FieldError> {
993        self.inner().src_addr_long(buf)
994    }
995
996    /// Get a field value by name (includes "fcs").
997    pub fn get_field(&self, buf: &[u8], name: &str) -> Option<Result<FieldValue, FieldError>> {
998        if name == "fcs" {
999            return Some(self.fcs(buf).map(FieldValue::U16));
1000        }
1001        self.inner().get_field(buf, name)
1002    }
1003
1004    /// Set a field value by name.
1005    pub fn set_field(
1006        &self,
1007        buf: &mut [u8],
1008        name: &str,
1009        value: FieldValue,
1010    ) -> Option<Result<(), FieldError>> {
1011        // FCS is computed, not set directly
1012        if name == "fcs" {
1013            return Some(Err(FieldError::InvalidValue(
1014                "FCS is computed automatically, cannot set directly".into(),
1015            )));
1016        }
1017        self.inner().set_field(buf, name, value)
1018    }
1019
1020    /// Get the list of field names.
1021    #[must_use]
1022    pub fn field_names() -> &'static [&'static str] {
1023        DOT15D4_FCS_FIELDS
1024    }
1025
1026    /// Compute hash for packet matching.
1027    #[must_use]
1028    pub fn hashret(&self, buf: &[u8]) -> Vec<u8> {
1029        self.inner().hashret(buf)
1030    }
1031}
1032
1033impl Layer for Dot15d4FcsLayer {
1034    fn kind(&self) -> LayerKind {
1035        LayerKind::Dot15d4Fcs
1036    }
1037
1038    fn summary(&self, buf: &[u8]) -> String {
1039        let inner_summary = self.inner().summary(buf);
1040        let fcs_str = self
1041            .fcs(buf)
1042            .map(|f| format!(" FCS={f:#06x}"))
1043            .unwrap_or_default();
1044        format!("{inner_summary}{fcs_str}")
1045    }
1046
1047    fn header_len(&self, buf: &[u8]) -> usize {
1048        // Include FCS in the header length
1049        let inner_len = self.inner().header_len(buf);
1050        let total = inner_len + FCS_LEN;
1051        total.min(self.index.len())
1052    }
1053
1054    fn hashret(&self, buf: &[u8]) -> Vec<u8> {
1055        self.hashret(buf)
1056    }
1057
1058    fn answers(&self, buf: &[u8], other: &Self, other_buf: &[u8]) -> bool {
1059        self.inner().answers(buf, &other.inner(), other_buf)
1060    }
1061
1062    fn field_names(&self) -> &'static [&'static str] {
1063        DOT15D4_FCS_FIELDS
1064    }
1065}
1066
1067#[cfg(test)]
1068mod tests {
1069    use super::*;
1070
1071    /// Build a minimal data frame with short addressing:
1072    /// FCF: frame_type=1 (Data), dest_addr_mode=2 (Short), src_addr_mode=2 (Short),
1073    ///      panid_compress=1 (no src PAN ID)
1074    /// Seq: 0x05
1075    /// Dest PAN ID: 0x1234
1076    /// Dest Addr: 0xFFFF
1077    /// Src Addr: 0x0001
1078    fn sample_data_frame_short() -> Vec<u8> {
1079        // FCF: frame_type=1, security=0, pending=0, ackreq=1, panid_compress=1
1080        //      dest_addr_mode=2, frame_ver=0, src_addr_mode=2
1081        // Bits: src_addr_mode(2)=10, frame_ver=00, dest_addr_mode(2)=10, reserved=000,
1082        //       panid_compress=1, ackreq=1, pending=0, security=0, frame_type=001
1083        // Byte 0 (bits 0-7): 0_1_1_0_0_001 = 0x61
1084        // Byte 1 (bits 8-15): 10_00_10_00 = 0x88
1085        let mut buf = Vec::new();
1086        buf.extend_from_slice(&[0x61, 0x88]); // FCF (LE)
1087        buf.push(0x05); // Sequence number
1088        buf.extend_from_slice(&[0x34, 0x12]); // Dest PAN ID (LE)
1089        buf.extend_from_slice(&[0xFF, 0xFF]); // Dest Addr Short (LE)
1090        buf.extend_from_slice(&[0x01, 0x00]); // Src Addr Short (LE)
1091        buf
1092    }
1093
1094    /// Build a data frame with long addressing and no PAN ID compression.
1095    fn sample_data_frame_long() -> Vec<u8> {
1096        // FCF: frame_type=1, dest_addr_mode=3 (Long), src_addr_mode=3 (Long),
1097        //      panid_compress=0
1098        // Byte 0 (bits 0-7): 0_0_0_0_0_001 = 0x01
1099        // Byte 1 (bits 8-15): 11_00_11_00 = 0xCC
1100        let mut buf = Vec::new();
1101        buf.extend_from_slice(&[0x01, 0xCC]); // FCF
1102        buf.push(0x0A); // Seqnum
1103        buf.extend_from_slice(&[0x34, 0x12]); // Dest PAN ID
1104        buf.extend_from_slice(&[0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01]); // Dest Addr Long
1105        buf.extend_from_slice(&[0xCD, 0xAB]); // Src PAN ID
1106        buf.extend_from_slice(&[0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11]); // Src Addr Long
1107        buf
1108    }
1109
1110    /// Build a minimal ACK frame (no addressing).
1111    fn sample_ack_frame() -> Vec<u8> {
1112        // FCF: frame_type=2, all addr modes = 0
1113        // Byte 0: 0_0_0_0_0_010 = 0x02
1114        // Byte 1: 00_00_00_00 = 0x00
1115        vec![0x02, 0x00, 0x05] // FCF + seqnum
1116    }
1117
1118    #[test]
1119    fn test_fcf_helpers() {
1120        let fcf = build_fcf(1, false, false, true, true, 2, 0, 2);
1121        assert_eq!(fcf_frame_type(fcf), 1);
1122        assert!(!fcf_security(fcf));
1123        assert!(!fcf_pending(fcf));
1124        assert!(fcf_ackreq(fcf));
1125        assert!(fcf_panid_compress(fcf));
1126        assert_eq!(fcf_dest_addr_mode(fcf), 2);
1127        assert_eq!(fcf_frame_ver(fcf), 0);
1128        assert_eq!(fcf_src_addr_mode(fcf), 2);
1129    }
1130
1131    #[test]
1132    fn test_build_fcf_roundtrip() {
1133        for ft in 0..=5u8 {
1134            for dam in 0..=3u8 {
1135                for sam in 0..=3u8 {
1136                    let fcf = build_fcf(ft, true, false, true, false, dam, 1, sam);
1137                    assert_eq!(fcf_frame_type(fcf), ft);
1138                    assert!(fcf_security(fcf));
1139                    assert!(!fcf_pending(fcf));
1140                    assert!(fcf_ackreq(fcf));
1141                    assert!(!fcf_panid_compress(fcf));
1142                    assert_eq!(fcf_dest_addr_mode(fcf), dam);
1143                    assert_eq!(fcf_frame_ver(fcf), 1);
1144                    assert_eq!(fcf_src_addr_mode(fcf), sam);
1145                }
1146            }
1147        }
1148    }
1149
1150    #[test]
1151    fn test_compute_header_len() {
1152        // ACK frame: no addressing
1153        let fcf_ack = build_fcf(2, false, false, false, false, 0, 0, 0);
1154        assert_eq!(compute_header_len(fcf_ack), 3); // FCF + seqnum
1155
1156        // Data frame with short dest+src, panid compress
1157        let fcf_data = build_fcf(1, false, false, true, true, 2, 0, 2);
1158        // 3 (base) + 2 (dest PAN) + 2 (dest short) + 2 (src short) = 9
1159        assert_eq!(compute_header_len(fcf_data), 9);
1160
1161        // Data frame with short dest+src, no panid compress
1162        let fcf_data2 = build_fcf(1, false, false, true, false, 2, 0, 2);
1163        // 3 + 2 (dest PAN) + 2 (dest short) + 2 (src PAN) + 2 (src short) = 11
1164        assert_eq!(compute_header_len(fcf_data2), 11);
1165
1166        // Data frame with long dest, short src, panid compress
1167        let fcf_data3 = build_fcf(1, false, false, false, true, 3, 0, 2);
1168        // 3 + 2 (dest PAN) + 8 (dest long) + 2 (src short) = 15
1169        assert_eq!(compute_header_len(fcf_data3), 15);
1170
1171        // Data frame with long dest+src, no compress
1172        let fcf_data4 = build_fcf(1, false, false, false, false, 3, 0, 3);
1173        // 3 + 2 (dest PAN) + 8 (dest long) + 2 (src PAN) + 8 (src long) = 23
1174        assert_eq!(compute_header_len(fcf_data4), 23);
1175    }
1176
1177    #[test]
1178    fn test_parse_data_frame_short() {
1179        let buf = sample_data_frame_short();
1180        let layer = Dot15d4Layer::new(0, buf.len());
1181
1182        assert_eq!(layer.fcf_frametype(&buf).unwrap(), 1);
1183        assert!(!layer.fcf_security(&buf).unwrap());
1184        assert!(!layer.fcf_pending(&buf).unwrap());
1185        assert!(layer.fcf_ackreq(&buf).unwrap());
1186        assert!(layer.fcf_panidcompress(&buf).unwrap());
1187        assert_eq!(layer.fcf_destaddrmode(&buf).unwrap(), 2);
1188        assert_eq!(layer.fcf_framever(&buf).unwrap(), 0);
1189        assert_eq!(layer.fcf_srcaddrmode(&buf).unwrap(), 2);
1190        assert_eq!(layer.seqnum(&buf).unwrap(), 0x05);
1191
1192        assert_eq!(layer.dest_panid(&buf).unwrap(), Some(0x1234));
1193        assert_eq!(layer.dest_addr_short(&buf).unwrap(), Some(0xFFFF));
1194        assert_eq!(layer.dest_addr_long(&buf).unwrap(), None);
1195
1196        // PAN ID compressed, so src_panid should be None
1197        assert_eq!(layer.src_panid(&buf).unwrap(), None);
1198        assert_eq!(layer.src_addr_short(&buf).unwrap(), Some(0x0001));
1199        assert_eq!(layer.src_addr_long(&buf).unwrap(), None);
1200
1201        // Header length = 9
1202        assert_eq!(layer.header_len(&buf), 9);
1203    }
1204
1205    #[test]
1206    fn test_parse_data_frame_long() {
1207        let buf = sample_data_frame_long();
1208        let layer = Dot15d4Layer::new(0, buf.len());
1209
1210        assert_eq!(layer.fcf_frametype(&buf).unwrap(), 1);
1211        assert_eq!(layer.fcf_destaddrmode(&buf).unwrap(), 3);
1212        assert_eq!(layer.fcf_srcaddrmode(&buf).unwrap(), 3);
1213        assert!(!layer.fcf_panidcompress(&buf).unwrap());
1214        assert_eq!(layer.seqnum(&buf).unwrap(), 0x0A);
1215
1216        assert_eq!(layer.dest_panid(&buf).unwrap(), Some(0x1234));
1217        assert_eq!(
1218            layer.dest_addr_long(&buf).unwrap(),
1219            Some(0x0102030405060708)
1220        );
1221        assert_eq!(layer.dest_addr_short(&buf).unwrap(), None);
1222
1223        assert_eq!(layer.src_panid(&buf).unwrap(), Some(0xABCD));
1224        assert_eq!(layer.src_addr_long(&buf).unwrap(), Some(0x1112131415161718));
1225        assert_eq!(layer.src_addr_short(&buf).unwrap(), None);
1226
1227        // Header: 3 + 2 + 8 + 2 + 8 = 23
1228        assert_eq!(layer.header_len(&buf), 23);
1229    }
1230
1231    #[test]
1232    fn test_parse_ack_frame() {
1233        let buf = sample_ack_frame();
1234        let layer = Dot15d4Layer::new(0, buf.len());
1235
1236        assert_eq!(layer.fcf_frametype(&buf).unwrap(), 2);
1237        assert_eq!(layer.fcf_destaddrmode(&buf).unwrap(), 0);
1238        assert_eq!(layer.fcf_srcaddrmode(&buf).unwrap(), 0);
1239        assert_eq!(layer.seqnum(&buf).unwrap(), 0x05);
1240
1241        assert_eq!(layer.dest_panid(&buf).unwrap(), None);
1242        assert_eq!(layer.dest_addr_short(&buf).unwrap(), None);
1243        assert_eq!(layer.src_panid(&buf).unwrap(), None);
1244        assert_eq!(layer.src_addr_short(&buf).unwrap(), None);
1245
1246        assert_eq!(layer.header_len(&buf), 3);
1247    }
1248
1249    #[test]
1250    fn test_ack_answers() {
1251        let data_buf = sample_data_frame_short();
1252        let data_layer = Dot15d4Layer::new(0, data_buf.len());
1253
1254        // ACK with matching sequence number
1255        let ack_buf = sample_ack_frame();
1256        let ack_layer = Dot15d4Layer::new(0, ack_buf.len());
1257
1258        assert!(ack_layer.answers(&ack_buf, &data_layer, &data_buf));
1259    }
1260
1261    #[test]
1262    fn test_ack_does_not_answer_wrong_seq() {
1263        let data_buf = sample_data_frame_short(); // seqnum = 0x05
1264        let data_layer = Dot15d4Layer::new(0, data_buf.len());
1265
1266        // ACK with different sequence number
1267        let mut ack_buf = sample_ack_frame();
1268        ack_buf[2] = 0x06; // Different seqnum
1269        let ack_layer = Dot15d4Layer::new(0, ack_buf.len());
1270
1271        assert!(!ack_layer.answers(&ack_buf, &data_layer, &data_buf));
1272    }
1273
1274    #[test]
1275    fn test_summary() {
1276        let buf = sample_data_frame_short();
1277        let layer = Dot15d4Layer::new(0, buf.len());
1278        let summary = layer.summary(&buf);
1279        assert!(summary.contains("Data"));
1280        assert!(summary.contains("ackreq(true)"));
1281        assert!(summary.contains("Short"));
1282        assert!(summary.contains("Seq#5"));
1283    }
1284
1285    #[test]
1286    fn test_get_field() {
1287        let buf = sample_data_frame_short();
1288        let layer = Dot15d4Layer::new(0, buf.len());
1289
1290        let ft = layer.get_field(&buf, "fcf_frametype").unwrap().unwrap();
1291        assert_eq!(ft, FieldValue::U8(1));
1292
1293        let seq = layer.get_field(&buf, "seqnum").unwrap().unwrap();
1294        assert_eq!(seq, FieldValue::U8(5));
1295
1296        let dp = layer.get_field(&buf, "dest_panid").unwrap().unwrap();
1297        assert_eq!(dp, FieldValue::U16(0x1234));
1298
1299        assert!(layer.get_field(&buf, "nonexistent").is_none());
1300    }
1301
1302    #[test]
1303    fn test_set_field() {
1304        let mut buf = sample_data_frame_short();
1305        let layer = Dot15d4Layer::new(0, buf.len());
1306
1307        layer
1308            .set_field(&mut buf, "seqnum", FieldValue::U8(42))
1309            .unwrap()
1310            .unwrap();
1311        assert_eq!(layer.seqnum(&buf).unwrap(), 42);
1312
1313        layer
1314            .set_field(&mut buf, "fcf_ackreq", FieldValue::Bool(false))
1315            .unwrap()
1316            .unwrap();
1317        assert!(!layer.fcf_ackreq(&buf).unwrap());
1318    }
1319
1320    #[test]
1321    fn test_set_dest_panid() {
1322        let mut buf = sample_data_frame_short();
1323        let layer = Dot15d4Layer::new(0, buf.len());
1324
1325        layer.set_dest_panid(&mut buf, 0xABCD).unwrap();
1326        assert_eq!(layer.dest_panid(&buf).unwrap(), Some(0xABCD));
1327    }
1328
1329    #[test]
1330    fn test_set_dest_addr_short() {
1331        let mut buf = sample_data_frame_short();
1332        let layer = Dot15d4Layer::new(0, buf.len());
1333
1334        layer.set_dest_addr_short(&mut buf, 0x1234).unwrap();
1335        assert_eq!(layer.dest_addr_short(&buf).unwrap(), Some(0x1234));
1336    }
1337
1338    #[test]
1339    fn test_set_src_addr_short() {
1340        let mut buf = sample_data_frame_short();
1341        let layer = Dot15d4Layer::new(0, buf.len());
1342
1343        layer.set_src_addr_short(&mut buf, 0x5678).unwrap();
1344        assert_eq!(layer.src_addr_short(&buf).unwrap(), Some(0x5678));
1345    }
1346
1347    #[test]
1348    fn test_fcs_layer_basic() {
1349        let mut frame = sample_data_frame_short();
1350        // Append FCS
1351        let fcs = crc::compute_fcs(&frame);
1352        frame.extend_from_slice(&fcs);
1353
1354        let layer = Dot15d4FcsLayer::new(0, frame.len());
1355        assert_eq!(layer.fcf_frametype(&frame).unwrap(), 1);
1356        assert_eq!(layer.seqnum(&frame).unwrap(), 0x05);
1357        assert!(layer.verify_fcs(&frame).unwrap());
1358    }
1359
1360    #[test]
1361    fn test_fcs_layer_corrupted() {
1362        let mut frame = sample_data_frame_short();
1363        // Append wrong FCS
1364        frame.extend_from_slice(&[0x00, 0x00]);
1365
1366        let layer = Dot15d4FcsLayer::new(0, frame.len());
1367        assert!(!layer.verify_fcs(&frame).unwrap());
1368    }
1369
1370    #[test]
1371    fn test_fcs_layer_get_field() {
1372        let mut frame = sample_data_frame_short();
1373        let fcs_val = crc::crc_ccitt_kermit(&frame);
1374        let fcs_bytes = fcs_val.to_le_bytes();
1375        frame.extend_from_slice(&fcs_bytes);
1376
1377        let layer = Dot15d4FcsLayer::new(0, frame.len());
1378        let fcs = layer.get_field(&frame, "fcs").unwrap().unwrap();
1379        assert_eq!(fcs, FieldValue::U16(fcs_val));
1380
1381        // Also access regular fields
1382        let seq = layer.get_field(&frame, "seqnum").unwrap().unwrap();
1383        assert_eq!(seq, FieldValue::U8(5));
1384    }
1385
1386    #[test]
1387    fn test_fcs_layer_summary() {
1388        let mut frame = sample_data_frame_short();
1389        let fcs_bytes = crc::compute_fcs(&frame);
1390        frame.extend_from_slice(&fcs_bytes);
1391
1392        let layer = Dot15d4FcsLayer::new(0, frame.len());
1393        let summary = layer.summary(&frame);
1394        assert!(summary.contains("802.15.4"));
1395        assert!(summary.contains("FCS="));
1396    }
1397
1398    #[test]
1399    fn test_format_long_addr() {
1400        let addr: u64 = 0x0102030405060708;
1401        let formatted = Dot15d4Layer::format_long_addr(addr);
1402        assert_eq!(formatted, "01:02:03:04:05:06:07:08");
1403    }
1404
1405    #[test]
1406    fn test_validate() {
1407        assert!(Dot15d4Layer::validate(&[0x00, 0x00, 0x00], 0).is_ok());
1408        assert!(Dot15d4Layer::validate(&[0x00, 0x00], 0).is_err());
1409        assert!(Dot15d4Layer::validate(&[0x00, 0x00, 0x00], 1).is_err());
1410    }
1411
1412    #[test]
1413    fn test_field_names() {
1414        let names = Dot15d4Layer::field_names();
1415        assert!(names.contains(&"fcf_frametype"));
1416        assert!(names.contains(&"seqnum"));
1417        assert!(names.contains(&"dest_panid"));
1418        assert!(names.contains(&"src_addr_long"));
1419    }
1420
1421    #[test]
1422    fn test_fcs_field_names() {
1423        let names = Dot15d4FcsLayer::field_names();
1424        assert!(names.contains(&"fcs"));
1425        assert!(names.contains(&"fcf_frametype"));
1426    }
1427
1428    #[test]
1429    fn test_fcf_writers() {
1430        let mut buf = sample_data_frame_short();
1431        let layer = Dot15d4Layer::new(0, buf.len());
1432
1433        // Change frame type to Beacon (0)
1434        layer.set_fcf_frametype(&mut buf, 0).unwrap();
1435        assert_eq!(layer.fcf_frametype(&buf).unwrap(), 0);
1436
1437        // Toggle security
1438        layer.set_fcf_security(&mut buf, true).unwrap();
1439        assert!(layer.fcf_security(&buf).unwrap());
1440
1441        // Toggle pending
1442        layer.set_fcf_pending(&mut buf, true).unwrap();
1443        assert!(layer.fcf_pending(&buf).unwrap());
1444
1445        // Change frame version
1446        layer.set_fcf_framever(&mut buf, 1).unwrap();
1447        assert_eq!(layer.fcf_framever(&buf).unwrap(), 1);
1448
1449        // Other fields should remain intact
1450        assert!(layer.fcf_ackreq(&buf).unwrap());
1451        assert!(layer.fcf_panidcompress(&buf).unwrap());
1452        assert_eq!(layer.fcf_destaddrmode(&buf).unwrap(), 2);
1453        assert_eq!(layer.fcf_srcaddrmode(&buf).unwrap(), 2);
1454    }
1455}