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