Skip to main content

stackforge_core/layer/
mod.rs

1//! Layer definitions and enum dispatch for protocol handling.
2//!
3//! This module implements the "Lazy Zero-Copy View" architecture where layers
4//! are represented as lightweight views into a raw packet buffer.
5
6use enum_dispatch::enum_dispatch;
7
8pub mod arp;
9pub mod bindings;
10pub mod dhcp;
11pub mod dns;
12pub mod dot11;
13pub mod dot15d4;
14pub mod ethernet;
15pub mod field;
16pub mod field_ext;
17pub mod ftp;
18pub mod generic;
19pub mod http;
20pub mod http2;
21pub mod icmp;
22pub mod icmpv6;
23pub mod imap;
24pub mod ipv4;
25pub mod ipv6;
26pub mod l2tp;
27pub mod modbus;
28pub mod mqtt;
29pub mod mqttsn;
30pub mod neighbor;
31pub mod pop3;
32pub mod quic;
33pub mod raw;
34pub mod smtp;
35pub mod ssh;
36pub mod stack;
37pub mod tcp;
38pub mod tftp;
39pub mod tls;
40pub mod udp;
41pub mod zwave;
42
43use std::ops::Range;
44
45// Re-export layer types
46pub use arp::{ArpBuilder, ArpLayer};
47pub use bindings::{LAYER_BINDINGS, LayerBinding};
48pub use ethernet::{Dot3Builder, Dot3Layer, EthernetBuilder, EthernetLayer};
49pub use field::{BytesField, Field, FieldDesc, FieldError, FieldType, FieldValue, MacAddress};
50pub use ftp::{
51    FTP_CONTROL_PORT, FTP_DATA_PORT, FTP_FIELD_NAMES, FTP_MIN_HEADER_LEN, FtpBuilder, FtpLayer,
52    is_ftp_payload,
53};
54pub use http::{HTTP_FIELD_NAMES, HttpLayer, HttpRequestBuilder, HttpResponseBuilder};
55pub use http2::{HTTP2_FIELD_NAMES, Http2Builder, Http2FrameBuilder, Http2Layer};
56pub use icmp::{ICMP_MIN_HEADER_LEN, IcmpBuilder, IcmpLayer, icmp_checksum, verify_icmp_checksum};
57pub use icmpv6::{
58    ICMPV6_MIN_HEADER_LEN, Icmpv6Builder, Icmpv6Layer, icmpv6_checksum, verify_icmpv6_checksum,
59};
60pub use imap::{
61    IMAP_FIELD_NAMES, IMAP_MIN_HEADER_LEN, IMAP_PORT, ImapBuilder, ImapLayer, is_imap_payload,
62};
63pub use ipv4::{Ipv4Builder, Ipv4Flags, Ipv4Layer, Ipv4Options, Ipv4Route};
64pub use ipv6::{IPV6_HEADER_LEN, Ipv6Builder, Ipv6Layer};
65pub use l2tp::{L2TP_FIELD_NAMES, L2TP_MIN_HEADER_LEN, L2TP_PORT, L2tpBuilder, L2tpLayer};
66pub use modbus::{
67    MODBUS_FIELD_NAMES, MODBUS_MIN_HEADER_LEN, MODBUS_TCP_PORT, ModbusBuilder, ModbusLayer,
68    is_modbus_tcp_payload,
69};
70pub use mqtt::{
71    MQTT_FIELD_NAMES, MQTT_MIN_HEADER_LEN, MQTT_PORT, MqttBuilder, MqttLayer, is_mqtt_payload,
72};
73pub use mqttsn::{
74    MQTTSN_FIELD_NAMES, MQTTSN_MIN_HEADER_LEN, MQTTSN_PORT, MqttSnBuilder, MqttSnLayer,
75    is_mqttsn_payload,
76};
77pub use neighbor::{NeighborCache, NeighborResolver};
78pub use pop3::{
79    POP3_FIELD_NAMES, POP3_MIN_HEADER_LEN, POP3_PORT, Pop3Builder, Pop3Layer, is_pop3_payload,
80};
81pub use raw::{RAW_FIELDS, RawBuilder, RawLayer};
82pub use smtp::{
83    SMTP_FIELD_NAMES, SMTP_MIN_HEADER_LEN, SMTP_PORT, SmtpBuilder, SmtpLayer, is_smtp_payload,
84};
85pub use ssh::{SSH_BINARY_HEADER_LEN, SSH_PORT, SshBuilder, SshLayer};
86pub use stack::{IntoLayerStackEntry, LayerStack, LayerStackEntry};
87pub use tcp::{
88    TCP_FIELDS, TCP_MAX_HEADER_LEN, TCP_MIN_HEADER_LEN, TCP_SERVICES, TcpAoValue, TcpBuilder,
89    TcpFlags, TcpLayer, TcpOption, TcpOptionKind, TcpOptions, TcpOptionsBuilder, TcpSackBlock,
90    TcpTimestamp, service_name, service_port, tcp_checksum, tcp_checksum_ipv4, verify_tcp_checksum,
91};
92pub use tftp::{TFTP_MIN_HEADER_LEN, TFTP_PORT, TftpBuilder, TftpLayer, is_tftp_payload};
93pub use tls::{
94    TLS_FIELDS, TLS_PORT, TLS_RECORD_HEADER_LEN, TlsAlertBuilder, TlsCcsBuilder, TlsContentType,
95    TlsLayer, TlsRecordBuilder, TlsVersion,
96};
97pub use udp::{
98    UDP_HEADER_LEN, UdpBuilder, UdpLayer, udp_checksum_ipv4, udp_checksum_ipv6,
99    verify_udp_checksum_ipv4, verify_udp_checksum_ipv6,
100};
101pub use zwave::{
102    ZWAVE_FIELD_NAMES, ZWAVE_HEADER_LEN, ZWAVE_MIN_HEADER_LEN, ZWaveBuilder, ZWaveLayer,
103};
104
105/// Identifies the type of network protocol layer.
106#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
107#[repr(u8)]
108pub enum LayerKind {
109    Ethernet = 0,
110    Dot3 = 1,
111    Arp = 2,
112    Ipv4 = 3,
113    Ipv6 = 4,
114    Icmp = 5,
115    Icmpv6 = 6,
116    Tcp = 7,
117    Udp = 8,
118    Dns = 9,
119    Dot1Q = 10,
120    Dot1AD = 11,
121    Dot1AH = 12,
122    LLC = 13,
123    SNAP = 14,
124    Ssh = 15,
125    Tls = 16,
126    Dot15d4 = 17,
127    Dot15d4Fcs = 18,
128    Dot11 = 19,
129    Http = 20,
130    Quic = 21,
131    Generic = 22,
132    Http2 = 23,
133    L2tp = 24,
134    Mqtt = 25,
135    MqttSn = 26,
136    Modbus = 27,
137    ZWave = 28,
138    Ftp = 29,
139    Tftp = 30,
140    Smtp = 31,
141    Pop3 = 32,
142    Imap = 33,
143    Dhcp = 34,
144    Raw = 255,
145}
146
147impl LayerKind {
148    #[inline]
149    #[must_use]
150    pub const fn name(&self) -> &'static str {
151        match self {
152            Self::Ethernet => "Ethernet",
153            Self::Dot3 => "802.3",
154            Self::Arp => "ARP",
155            Self::Ipv4 => "IPv4",
156            Self::Ipv6 => "IPv6",
157            Self::Icmp => "ICMP",
158            Self::Icmpv6 => "ICMPv6",
159            Self::Tcp => "TCP",
160            Self::Udp => "UDP",
161            Self::Dns => "DNS",
162            Self::Dot1Q => "802.1Q",
163            Self::Dot1AD => "802.1AD",
164            Self::Dot1AH => "802.1AH",
165            Self::LLC => "LLC",
166            Self::SNAP => "SNAP",
167            Self::Ssh => "SSH",
168            Self::Tls => "TLS",
169            Self::Dot15d4 => "802.15.4",
170            Self::Dot15d4Fcs => "802.15.4 FCS",
171            Self::Dot11 => "802.11",
172            Self::Http => "HTTP",
173            Self::Quic => "QUIC",
174            Self::Generic => "Generic",
175            Self::Http2 => "HTTP/2",
176            Self::L2tp => "L2TP",
177            Self::Mqtt => "MQTT",
178            Self::MqttSn => "MQTT-SN",
179            Self::Modbus => "Modbus",
180            Self::ZWave => "Z-Wave",
181            Self::Ftp => "FTP",
182            Self::Tftp => "TFTP",
183            Self::Smtp => "SMTP",
184            Self::Pop3 => "POP3",
185            Self::Imap => "IMAP",
186            Self::Dhcp => "DHCP",
187            Self::Raw => "Raw",
188        }
189    }
190
191    #[inline]
192    #[must_use]
193    pub const fn min_header_size(&self) -> usize {
194        match self {
195            Self::Ethernet | Self::Dot3 => ethernet::ETHERNET_HEADER_LEN,
196            Self::Arp => arp::ARP_HEADER_LEN,
197            Self::Ipv4 => ipv4::IPV4_MIN_HEADER_LEN,
198            Self::Ipv6 => 40,
199            Self::Icmp | Self::Icmpv6 => 8,
200            Self::Tcp => tcp::TCP_MIN_HEADER_LEN,
201            Self::Udp => 8,
202            Self::Dns => 12,
203            Self::Dot1Q => 4,
204            Self::Dot1AD => 4,
205            Self::Dot1AH => 6,
206            Self::LLC => 3,
207            Self::SNAP => 5,
208            Self::Ssh => ssh::SSH_BINARY_HEADER_LEN,
209            Self::Tls => tls::TLS_RECORD_HEADER_LEN,
210            Self::Dot15d4 => 3,    // minimum: 2 bytes FCF + 1 byte seqnum
211            Self::Dot15d4Fcs => 5, // minimum: 2 bytes FCF + 1 byte seqnum + 2 bytes FCS
212            Self::Dot11 => dot11::DOT11_MIN_HEADER_LEN,
213            Self::Http => 14, // minimum: "GET / HTTP/1.1\r\n\r\n" is ~18 bytes, but use 14 as min
214            Self::Quic => quic::QUIC_MIN_HEADER_LEN,
215            Self::Generic => 0,
216            Self::Http2 => 9, // 9-byte frame header
217            Self::L2tp => l2tp::L2TP_MIN_HEADER_LEN,
218            Self::Mqtt => mqtt::MQTT_MIN_HEADER_LEN,
219            Self::MqttSn => mqttsn::MQTTSN_MIN_HEADER_LEN,
220            Self::Modbus => modbus::MODBUS_MIN_HEADER_LEN,
221            Self::ZWave => zwave::ZWAVE_MIN_HEADER_LEN,
222            Self::Ftp => ftp::FTP_MIN_HEADER_LEN,
223            Self::Tftp => tftp::TFTP_MIN_HEADER_LEN,
224            Self::Smtp => smtp::SMTP_MIN_HEADER_LEN,
225            Self::Pop3 => pop3::POP3_MIN_HEADER_LEN,
226            Self::Imap => imap::IMAP_MIN_HEADER_LEN,
227            Self::Dhcp => dhcp::DHCP_MIN_HEADER_LEN,
228            Self::Raw => 0,
229        }
230    }
231
232    /// Check if this is a link layer protocol
233    #[inline]
234    #[must_use]
235    pub const fn is_link_layer(&self) -> bool {
236        matches!(
237            self,
238            Self::Ethernet | Self::Dot3 | Self::Dot1Q | Self::Dot1AD | Self::Dot1AH
239        )
240    }
241
242    /// Check if this is a network layer protocol
243    #[inline]
244    #[must_use]
245    pub const fn is_network_layer(&self) -> bool {
246        matches!(self, Self::Ipv4 | Self::Ipv6 | Self::Arp)
247    }
248
249    /// Check if this is a transport layer protocol
250    #[inline]
251    #[must_use]
252    pub const fn is_transport_layer(&self) -> bool {
253        matches!(self, Self::Tcp | Self::Udp | Self::Icmp | Self::Icmpv6)
254    }
255}
256
257impl std::fmt::Display for LayerKind {
258    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
259        write!(f, "{}", self.name())
260    }
261}
262
263/// Index information for a layer within a packet buffer.
264#[derive(Debug, Clone, Copy, PartialEq, Eq)]
265pub struct LayerIndex {
266    pub kind: LayerKind,
267    pub start: usize,
268    pub end: usize,
269}
270
271impl LayerIndex {
272    #[inline]
273    #[must_use]
274    pub const fn new(kind: LayerKind, start: usize, end: usize) -> Self {
275        Self { kind, start, end }
276    }
277
278    #[inline]
279    #[must_use]
280    pub const fn range(&self) -> Range<usize> {
281        self.start..self.end
282    }
283
284    #[inline]
285    #[must_use]
286    pub const fn len(&self) -> usize {
287        self.end - self.start
288    }
289
290    #[inline]
291    #[must_use]
292    pub const fn is_empty(&self) -> bool {
293        self.start == self.end
294    }
295
296    /// Get the bytes for this layer from a buffer
297    #[inline]
298    #[must_use]
299    pub fn slice<'a>(&self, buf: &'a [u8]) -> &'a [u8] {
300        &buf[self.start..self.end.min(buf.len())]
301    }
302
303    /// Get mutable bytes for this layer from a buffer
304    #[inline]
305    pub fn slice_mut<'a>(&self, buf: &'a mut [u8]) -> &'a mut [u8] {
306        let end = self.end.min(buf.len());
307        &mut buf[self.start..end]
308    }
309
310    /// Get payload bytes (everything after this layer)
311    #[inline]
312    #[must_use]
313    pub fn payload<'a>(&self, buf: &'a [u8]) -> &'a [u8] {
314        &buf[self.end.min(buf.len())..]
315    }
316}
317
318/// Auto-dispatched trait for `LayerEnum`.
319///
320/// Generated by `enum_dispatch` to eliminate manual match-arm boilerplate
321/// and enable the compiler to inline dispatch calls more aggressively.
322#[enum_dispatch]
323pub trait LayerDispatch {
324    /// Get the kind of this layer.
325    fn dispatch_kind(&self) -> LayerKind;
326    /// Get the layer index (start/end offsets).
327    fn dispatch_index(&self) -> &LayerIndex;
328    /// Get a human-readable summary.
329    fn dispatch_summary(&self, buf: &[u8]) -> String;
330    /// Get the header length in bytes.
331    fn dispatch_header_len(&self, buf: &[u8]) -> usize;
332    /// Compute a hash for packet matching.
333    fn dispatch_hashret(&self, _buf: &[u8]) -> Vec<u8> {
334        vec![]
335    }
336    /// Get field names for this layer type.
337    fn dispatch_field_names(&self) -> &'static [&'static str];
338    /// Get a field value by name.
339    fn dispatch_get_field(&self, buf: &[u8], name: &str) -> Option<Result<FieldValue, FieldError>>;
340    /// Set a field value by name.
341    fn dispatch_set_field(
342        &self,
343        buf: &mut [u8],
344        name: &str,
345        value: FieldValue,
346    ) -> Option<Result<(), FieldError>>;
347    /// Get show-fields output.
348    fn dispatch_show_fields(&self, buf: &[u8]) -> Vec<(&'static str, String)>;
349}
350
351/// Implement `LayerDispatch` for a layer type.
352///
353/// Three forms:
354/// - `impl_layer_dispatch!(Type, show = fn)` — full dispatch via `Layer` trait
355/// - `impl_layer_dispatch!(Type, show = fn, readonly)` — read-only (set_field → None)
356/// - `impl_layer_dispatch!(Type, show = fn, inherent, kind = K, header_len = H)` — no `Layer` trait
357macro_rules! impl_layer_dispatch {
358    // Full form: type implements `Layer` trait + has get_field, set_field, field_names
359    ($ty:ty, show = $show_fn:expr) => {
360        impl LayerDispatch for $ty {
361            #[inline]
362            fn dispatch_kind(&self) -> LayerKind {
363                Layer::kind(self)
364            }
365            #[inline]
366            fn dispatch_index(&self) -> &LayerIndex {
367                &self.index
368            }
369            #[inline]
370            fn dispatch_summary(&self, buf: &[u8]) -> String {
371                Layer::summary(self, buf)
372            }
373            #[inline]
374            fn dispatch_header_len(&self, buf: &[u8]) -> usize {
375                Layer::header_len(self, buf)
376            }
377            #[inline]
378            fn dispatch_hashret(&self, buf: &[u8]) -> Vec<u8> {
379                Layer::hashret(self, buf)
380            }
381            #[inline]
382            fn dispatch_field_names(&self) -> &'static [&'static str] {
383                Layer::field_names(self)
384            }
385            #[inline]
386            fn dispatch_get_field(
387                &self,
388                buf: &[u8],
389                name: &str,
390            ) -> Option<Result<FieldValue, FieldError>> {
391                self.get_field(buf, name)
392            }
393            #[inline]
394            fn dispatch_set_field(
395                &self,
396                buf: &mut [u8],
397                name: &str,
398                value: FieldValue,
399            ) -> Option<Result<(), FieldError>> {
400                self.set_field(buf, name, value)
401            }
402            #[inline]
403            fn dispatch_show_fields(&self, buf: &[u8]) -> Vec<(&'static str, String)> {
404                $show_fn(self, buf)
405            }
406        }
407    };
408    // Read-only variant: set_field always returns None
409    ($ty:ty, show = $show_fn:expr, readonly) => {
410        impl LayerDispatch for $ty {
411            #[inline]
412            fn dispatch_kind(&self) -> LayerKind {
413                Layer::kind(self)
414            }
415            #[inline]
416            fn dispatch_index(&self) -> &LayerIndex {
417                &self.index
418            }
419            #[inline]
420            fn dispatch_summary(&self, buf: &[u8]) -> String {
421                Layer::summary(self, buf)
422            }
423            #[inline]
424            fn dispatch_header_len(&self, buf: &[u8]) -> usize {
425                Layer::header_len(self, buf)
426            }
427            #[inline]
428            fn dispatch_hashret(&self, buf: &[u8]) -> Vec<u8> {
429                Layer::hashret(self, buf)
430            }
431            #[inline]
432            fn dispatch_field_names(&self) -> &'static [&'static str] {
433                Layer::field_names(self)
434            }
435            #[inline]
436            fn dispatch_get_field(
437                &self,
438                buf: &[u8],
439                name: &str,
440            ) -> Option<Result<FieldValue, FieldError>> {
441                self.get_field(buf, name)
442            }
443            #[inline]
444            fn dispatch_set_field(
445                &self,
446                _buf: &mut [u8],
447                _name: &str,
448                _value: FieldValue,
449            ) -> Option<Result<(), FieldError>> {
450                None
451            }
452            #[inline]
453            fn dispatch_show_fields(&self, buf: &[u8]) -> Vec<(&'static str, String)> {
454                $show_fn(self, buf)
455            }
456        }
457    };
458    // Inherent variant: type does NOT implement `Layer` trait, delegates to inherent methods
459    ($ty:ty, show = $show_fn:expr, inherent, kind = $kind:expr, header_len = $hdr:expr) => {
460        impl LayerDispatch for $ty {
461            #[inline]
462            fn dispatch_kind(&self) -> LayerKind {
463                $kind
464            }
465            #[inline]
466            fn dispatch_index(&self) -> &LayerIndex {
467                &self.index
468            }
469            #[inline]
470            fn dispatch_summary(&self, buf: &[u8]) -> String {
471                self.summary(buf)
472            }
473            #[inline]
474            fn dispatch_header_len(&self, _buf: &[u8]) -> usize {
475                $hdr
476            }
477            #[inline]
478            fn dispatch_hashret(&self, buf: &[u8]) -> Vec<u8> {
479                self.hashret(buf)
480            }
481            #[inline]
482            fn dispatch_field_names(&self) -> &'static [&'static str] {
483                <$ty>::field_names()
484            }
485            #[inline]
486            fn dispatch_get_field(
487                &self,
488                buf: &[u8],
489                name: &str,
490            ) -> Option<Result<FieldValue, FieldError>> {
491                self.get_field(buf, name)
492            }
493            #[inline]
494            fn dispatch_set_field(
495                &self,
496                buf: &mut [u8],
497                name: &str,
498                value: FieldValue,
499            ) -> Option<Result<(), FieldError>> {
500                self.set_field(buf, name, value)
501            }
502            #[inline]
503            fn dispatch_show_fields(&self, buf: &[u8]) -> Vec<(&'static str, String)> {
504                $show_fn(self, buf)
505            }
506        }
507    };
508}
509
510/// Trait for types that can act as a network protocol layer.
511///
512/// This trait defines the core interface for all protocol layers,
513/// including methods for packet matching (hashret/answers) and
514/// padding extraction
515pub trait Layer {
516    /// Get the kind of this layer
517    fn kind(&self) -> LayerKind;
518
519    /// Get a human-readable summary of this layer
520    fn summary(&self, data: &[u8]) -> String;
521
522    /// Get the header length for this layer
523    fn header_len(&self, data: &[u8]) -> usize;
524
525    /// Compute a hash for packet matching.
526    fn hashret(&self, _data: &[u8]) -> Vec<u8> {
527        vec![]
528    }
529
530    /// Check if this packet answers another packet.
531    fn answers(&self, _data: &[u8], _other: &Self, _other_data: &[u8]) -> bool {
532        false
533    }
534
535    /// Extract padding from the packet.
536    fn extract_padding<'a>(&self, data: &'a [u8]) -> (&'a [u8], &'a [u8]) {
537        let header_len = self.header_len(data);
538        (&data[header_len..], &[])
539    }
540
541    /// Get the list of field names for this layer
542    fn field_names(&self) -> &'static [&'static str] {
543        &[]
544    }
545}
546
547/// Enum dispatch for protocol layers.
548///
549/// The `LayerDispatch` trait is auto-implemented by `enum_dispatch`,
550/// eliminating manual match arms and enabling better inlining.
551#[derive(Debug, Clone)]
552#[enum_dispatch(LayerDispatch)]
553pub enum LayerEnum {
554    Ethernet(EthernetLayer),
555    Dot3(Dot3Layer),
556    Arp(ArpLayer),
557    Ipv4(Ipv4Layer),
558    Ipv6(Ipv6Layer),
559    Icmp(IcmpLayer),
560    Icmpv6(Icmpv6Layer),
561    Tcp(TcpLayer),
562    Udp(UdpLayer),
563    Dns(DnsLayer),
564    Ssh(SshLayer),
565    Tls(TlsLayer),
566    Dot15d4(dot15d4::Dot15d4Layer),
567    Dot15d4Fcs(dot15d4::Dot15d4FcsLayer),
568    Dot11(dot11::Dot11Layer),
569    Http(http::HttpLayer),
570    Http2(http2::Http2Layer),
571    Quic(quic::QuicLayer),
572    L2tp(l2tp::L2tpLayer),
573    Mqtt(mqtt::MqttLayer),
574    MqttSn(mqttsn::MqttSnLayer),
575    Modbus(modbus::ModbusLayer),
576    ZWave(zwave::ZWaveLayer),
577    Ftp(ftp::FtpLayer),
578    Tftp(tftp::TftpLayer),
579    Smtp(smtp::SmtpLayer),
580    Pop3(pop3::Pop3Layer),
581    Imap(imap::ImapLayer),
582    Dhcp(dhcp::DhcpLayer),
583    Raw(RawLayer),
584}
585
586impl LayerEnum {
587    /// Delegate to `LayerDispatch::dispatch_kind` (auto-generated by `enum_dispatch`).
588    #[inline]
589    #[must_use]
590    pub fn kind(&self) -> LayerKind {
591        self.dispatch_kind()
592    }
593
594    /// Delegate to `LayerDispatch::dispatch_index`.
595    #[inline]
596    #[must_use]
597    pub fn index(&self) -> &LayerIndex {
598        self.dispatch_index()
599    }
600
601    /// Delegate to `LayerDispatch::dispatch_summary`.
602    #[must_use]
603    pub fn summary(&self, buf: &[u8]) -> String {
604        self.dispatch_summary(buf)
605    }
606
607    /// Delegate to `LayerDispatch::dispatch_hashret`.
608    #[must_use]
609    pub fn hashret(&self, buf: &[u8]) -> Vec<u8> {
610        self.dispatch_hashret(buf)
611    }
612
613    /// Delegate to `LayerDispatch::dispatch_header_len`.
614    #[must_use]
615    pub fn header_len(&self, buf: &[u8]) -> usize {
616        self.dispatch_header_len(buf)
617    }
618
619    /// Delegate to `LayerDispatch::dispatch_show_fields`.
620    #[must_use]
621    pub fn show_fields(&self, buf: &[u8]) -> Vec<(&'static str, String)> {
622        self.dispatch_show_fields(buf)
623    }
624
625    /// Delegate to `LayerDispatch::dispatch_get_field`.
626    #[must_use]
627    pub fn get_field(&self, buf: &[u8], name: &str) -> Option<Result<FieldValue, FieldError>> {
628        self.dispatch_get_field(buf, name)
629    }
630
631    /// Delegate to `LayerDispatch::dispatch_set_field`.
632    pub fn set_field(
633        &self,
634        buf: &mut [u8],
635        name: &str,
636        value: FieldValue,
637    ) -> Option<Result<(), FieldError>> {
638        self.dispatch_set_field(buf, name, value)
639    }
640
641    /// Delegate to `LayerDispatch::dispatch_field_names`.
642    #[must_use]
643    pub fn field_names(&self) -> &'static [&'static str] {
644        self.dispatch_field_names()
645    }
646}
647
648// ============================================================================
649// Show Fields Implementations
650// ============================================================================
651
652fn ethernet_show_fields(l: &EthernetLayer, buf: &[u8]) -> Vec<(&'static str, String)> {
653    let mut fields = Vec::new();
654    fields.push((
655        "dst",
656        l.dst(buf).map_or_else(|_| "?".into(), |m| m.to_string()),
657    ));
658    fields.push((
659        "src",
660        l.src(buf).map_or_else(|_| "?".into(), |m| m.to_string()),
661    ));
662    let etype = l.ethertype(buf).unwrap_or(0);
663    fields.push((
664        "type",
665        format!("{:#06x} ({})", etype, ethertype::name(etype)),
666    ));
667    fields
668}
669
670fn dot3_show_fields(l: &Dot3Layer, buf: &[u8]) -> Vec<(&'static str, String)> {
671    let mut fields = Vec::new();
672    fields.push((
673        "dst",
674        l.dst(buf).map_or_else(|_| "?".into(), |m| m.to_string()),
675    ));
676    fields.push((
677        "src",
678        l.src(buf).map_or_else(|_| "?".into(), |m| m.to_string()),
679    ));
680    fields.push((
681        "len",
682        l.len_field(buf)
683            .map_or_else(|_| "?".into(), |v| v.to_string()),
684    ));
685    fields
686}
687
688fn arp_show_fields(l: &ArpLayer, buf: &[u8]) -> Vec<(&'static str, String)> {
689    let mut fields = Vec::new();
690    let hwtype = l.hwtype(buf).unwrap_or(0);
691    fields.push((
692        "hwtype",
693        format!("{:#06x} ({})", hwtype, arp::hardware_type::name(hwtype)),
694    ));
695    let ptype = l.ptype(buf).unwrap_or(0);
696    fields.push(("ptype", format!("{ptype:#06x}")));
697    fields.push((
698        "hwlen",
699        l.hwlen(buf).map_or_else(|_| "?".into(), |v| v.to_string()),
700    ));
701    fields.push((
702        "plen",
703        l.plen(buf).map_or_else(|_| "?".into(), |v| v.to_string()),
704    ));
705    let op = l.op(buf).unwrap_or(0);
706    fields.push(("op", format!("{} ({})", op, arp::opcode::name(op))));
707    fields.push((
708        "hwsrc",
709        l.hwsrc_raw(buf)
710            .map_or_else(|_| "?".into(), |a| a.to_string()),
711    ));
712    fields.push((
713        "psrc",
714        l.psrc_raw(buf)
715            .map_or_else(|_| "?".into(), |a| a.to_string()),
716    ));
717    fields.push((
718        "hwdst",
719        l.hwdst_raw(buf)
720            .map_or_else(|_| "?".into(), |a| a.to_string()),
721    ));
722    fields.push((
723        "pdst",
724        l.pdst_raw(buf)
725            .map_or_else(|_| "?".into(), |a| a.to_string()),
726    ));
727    fields
728}
729
730fn ipv4_show_fields(l: &Ipv4Layer, buf: &[u8]) -> Vec<(&'static str, String)> {
731    let mut fields = Vec::new();
732    fields.push((
733        "version",
734        l.version(buf)
735            .map_or_else(|_| "?".into(), |v| v.to_string()),
736    ));
737    fields.push((
738        "ihl",
739        l.ihl(buf).map_or_else(|_| "?".into(), |v| v.to_string()),
740    ));
741    fields.push((
742        "tos",
743        l.tos(buf)
744            .map_or_else(|_| "?".into(), |v| format!("{v:#04x}")),
745    ));
746    fields.push((
747        "len",
748        l.total_len(buf)
749            .map_or_else(|_| "?".into(), |v| v.to_string()),
750    ));
751    fields.push((
752        "id",
753        l.id(buf)
754            .map_or_else(|_| "?".into(), |v| format!("{v:#06x}")),
755    ));
756    fields.push((
757        "flags",
758        l.flags(buf).map_or_else(|_| "?".into(), |f| f.to_string()),
759    ));
760    fields.push((
761        "frag",
762        l.frag_offset(buf)
763            .map_or_else(|_| "?".into(), |v| v.to_string()),
764    ));
765    fields.push((
766        "ttl",
767        l.ttl(buf).map_or_else(|_| "?".into(), |v| v.to_string()),
768    ));
769    let proto = l.protocol(buf).unwrap_or(0);
770    fields.push(("proto", format!("{} ({})", proto, l.protocol_name(buf))));
771    fields.push((
772        "chksum",
773        l.checksum(buf)
774            .map_or_else(|_| "?".into(), |v| format!("{v:#06x}")),
775    ));
776    fields.push((
777        "src",
778        l.src(buf).map_or_else(|_| "?".into(), |ip| ip.to_string()),
779    ));
780    fields.push((
781        "dst",
782        l.dst(buf).map_or_else(|_| "?".into(), |ip| ip.to_string()),
783    ));
784    // Options (if present)
785    let opts_len = l.options_len(buf);
786    if opts_len > 0 {
787        fields.push(("options", format!("[{opts_len} bytes]")));
788    }
789    fields
790}
791
792fn ipv6_show_fields(l: &Ipv6Layer, buf: &[u8]) -> Vec<(&'static str, String)> {
793    let mut fields = Vec::new();
794    fields.push((
795        "version",
796        l.version(buf)
797            .map_or_else(|_| "?".into(), |v| v.to_string()),
798    ));
799    fields.push((
800        "tc",
801        l.traffic_class(buf)
802            .map_or_else(|_| "?".into(), |v| format!("{v:#04x}")),
803    ));
804    fields.push((
805        "fl",
806        l.flow_label(buf)
807            .map_or_else(|_| "?".into(), |v| format!("{v:#07x}")),
808    ));
809    fields.push((
810        "plen",
811        l.payload_len(buf)
812            .map_or_else(|_| "?".into(), |v| v.to_string()),
813    ));
814    let nh = l.next_header(buf).unwrap_or(0);
815    fields.push(("nh", format!("{} ({})", nh, ipv4::protocol::to_name(nh))));
816    fields.push((
817        "hlim",
818        l.hop_limit(buf)
819            .map_or_else(|_| "?".into(), |v| v.to_string()),
820    ));
821    fields.push((
822        "src",
823        l.src(buf).map_or_else(|_| "?".into(), |a| a.to_string()),
824    ));
825    fields.push((
826        "dst",
827        l.dst(buf).map_or_else(|_| "?".into(), |a| a.to_string()),
828    ));
829    fields
830}
831
832fn icmp_show_fields(l: &IcmpLayer, buf: &[u8]) -> Vec<(&'static str, String)> {
833    let mut fields = Vec::new();
834
835    // Type field
836    fields.push((
837        "type",
838        l.icmp_type(buf).map_or_else(
839            |_| "?".into(),
840            |t: u8| format!("{} ({})", t, icmp::type_name(t)),
841        ),
842    ));
843
844    // Code field
845    fields.push((
846        "code",
847        l.code(buf)
848            .map_or_else(|_| "?".into(), |c: u8| c.to_string()),
849    ));
850
851    // Checksum field
852    fields.push((
853        "chksum",
854        l.checksum(buf)
855            .map_or_else(|_| "?".into(), |v: u16| format!("{v:#06x}")),
856    ));
857
858    // ID field (conditional)
859    if let Ok(Some(id)) = l.id(buf) {
860        fields.push(("id", format!("{id:#06x}")));
861    }
862
863    // Sequence field (conditional)
864    if let Ok(Some(seq)) = l.seq(buf) {
865        fields.push(("seq", seq.to_string()));
866    }
867
868    // Gateway field (for redirect)
869    if let Ok(Some(gateway)) = l.gateway(buf) {
870        fields.push(("gw", gateway.to_string()));
871    }
872
873    // Pointer field (for parameter problem)
874    if let Ok(Some(ptr)) = l.ptr(buf) {
875        fields.push(("ptr", ptr.to_string()));
876    }
877
878    // Next-hop MTU (for dest unreachable, fragmentation needed)
879    if let Ok(Some(mtu)) = l.next_hop_mtu(buf) {
880        fields.push(("mtu", mtu.to_string()));
881    }
882
883    // Timestamp fields (for timestamp request/reply)
884    if let Ok(Some(ts_ori)) = l.ts_ori(buf) {
885        fields.push(("ts_ori", ts_ori.to_string()));
886    }
887    if let Ok(Some(ts_rx)) = l.ts_rx(buf) {
888        fields.push(("ts_rx", ts_rx.to_string()));
889    }
890    if let Ok(Some(ts_tx)) = l.ts_tx(buf) {
891        fields.push(("ts_tx", ts_tx.to_string()));
892    }
893
894    // Address mask (for address mask request/reply)
895    if let Ok(Some(addr_mask)) = l.addr_mask(buf) {
896        fields.push(("addr_mask", addr_mask.to_string()));
897    }
898
899    fields
900}
901
902fn icmpv6_show_fields(l: &Icmpv6Layer, buf: &[u8]) -> Vec<(&'static str, String)> {
903    let mut fields = Vec::new();
904    let icmpv6_type = l.icmpv6_type(buf).unwrap_or(0);
905    let type_name = icmpv6::types::name(icmpv6_type);
906    fields.push(("type", format!("{icmpv6_type} ({type_name})")));
907    fields.push((
908        "code",
909        l.code(buf).map_or_else(|_| "?".into(), |v| v.to_string()),
910    ));
911    fields.push((
912        "chksum",
913        l.checksum(buf)
914            .map_or_else(|_| "?".into(), |v| format!("{v:#06x}")),
915    ));
916    if let Ok(Some(id)) = l.id(buf) {
917        fields.push(("id", format!("{id:#06x}")));
918    }
919    if let Ok(Some(seq)) = l.seq(buf) {
920        fields.push(("seq", seq.to_string()));
921    }
922    if let Ok(Some(target)) = l.target_addr(buf) {
923        fields.push(("tgt", target.to_string()));
924    }
925    if let Ok(Some(mtu)) = l.mtu(buf) {
926        fields.push(("mtu", mtu.to_string()));
927    }
928    fields
929}
930
931fn tcp_show_fields(l: &TcpLayer, buf: &[u8]) -> Vec<(&'static str, String)> {
932    let mut fields = Vec::new();
933    fields.push((
934        "sport",
935        l.src_port(buf)
936            .map_or_else(|_| "?".into(), |v| v.to_string()),
937    ));
938    fields.push((
939        "dport",
940        l.dst_port(buf)
941            .map_or_else(|_| "?".into(), |v| v.to_string()),
942    ));
943    fields.push((
944        "seq",
945        l.seq(buf).map_or_else(|_| "?".into(), |v| v.to_string()),
946    ));
947    fields.push((
948        "ack",
949        l.ack(buf).map_or_else(|_| "?".into(), |v| v.to_string()),
950    ));
951    fields.push((
952        "dataofs",
953        l.data_offset(buf)
954            .map_or_else(|_| "?".into(), |v| v.to_string()),
955    ));
956    fields.push((
957        "reserved",
958        l.reserved(buf)
959            .map_or_else(|_| "?".into(), |v| v.to_string()),
960    ));
961    fields.push((
962        "flags",
963        l.flags(buf).map_or_else(|_| "?".into(), |f| f.to_string()),
964    ));
965    fields.push((
966        "window",
967        l.window(buf).map_or_else(|_| "?".into(), |v| v.to_string()),
968    ));
969    fields.push((
970        "chksum",
971        l.checksum(buf)
972            .map_or_else(|_| "?".into(), |v| format!("{v:#06x}")),
973    ));
974    fields.push((
975        "urgptr",
976        l.urgent_ptr(buf)
977            .map_or_else(|_| "?".into(), |v| v.to_string()),
978    ));
979    // Options (if present)
980    let opts_len = l.options_len(buf);
981    if opts_len > 0 {
982        fields.push(("options", format!("[{opts_len} bytes]")));
983    }
984    fields
985}
986
987fn udp_show_fields(l: &UdpLayer, buf: &[u8]) -> Vec<(&'static str, String)> {
988    let mut fields = Vec::new();
989    fields.push((
990        "sport",
991        l.src_port(buf)
992            .map_or_else(|_| "?".into(), |v: u16| v.to_string()),
993    ));
994    fields.push((
995        "dport",
996        l.dst_port(buf)
997            .map_or_else(|_| "?".into(), |v: u16| v.to_string()),
998    ));
999    fields.push((
1000        "len",
1001        l.length(buf)
1002            .map_or_else(|_| "?".into(), |v: u16| v.to_string()),
1003    ));
1004    fields.push((
1005        "chksum",
1006        l.checksum(buf)
1007            .map_or_else(|_| "?".into(), |v: u16| format!("{v:#06x}")),
1008    ));
1009    fields
1010}
1011
1012fn dns_show_fields(l: &DnsLayer, buf: &[u8]) -> Vec<(&'static str, String)> {
1013    let mut fields = Vec::new();
1014    fields.push((
1015        "id",
1016        l.id(buf)
1017            .map_or_else(|_| "?".into(), |v| format!("{v:#06x}")),
1018    ));
1019    let qr = l.qr(buf).unwrap_or(false);
1020    fields.push(("qr", if qr { "response" } else { "query" }.to_string()));
1021    fields.push((
1022        "opcode",
1023        l.opcode(buf).map_or_else(
1024            |_| "?".into(),
1025            |v| format!("{} ({})", v, dns::types::opcode_name(v)),
1026        ),
1027    ));
1028    fields.push((
1029        "aa",
1030        l.aa(buf).map_or_else(|_| "?".into(), |v| v.to_string()),
1031    ));
1032    fields.push((
1033        "tc",
1034        l.tc(buf).map_or_else(|_| "?".into(), |v| v.to_string()),
1035    ));
1036    fields.push((
1037        "rd",
1038        l.rd(buf).map_or_else(|_| "?".into(), |v| v.to_string()),
1039    ));
1040    fields.push((
1041        "ra",
1042        l.ra(buf).map_or_else(|_| "?".into(), |v| v.to_string()),
1043    ));
1044    fields.push(("z", l.z(buf).map_or_else(|_| "?".into(), |v| v.to_string())));
1045    fields.push((
1046        "ad",
1047        l.ad(buf).map_or_else(|_| "?".into(), |v| v.to_string()),
1048    ));
1049    fields.push((
1050        "cd",
1051        l.cd(buf).map_or_else(|_| "?".into(), |v| v.to_string()),
1052    ));
1053    fields.push((
1054        "rcode",
1055        l.rcode(buf).map_or_else(
1056            |_| "?".into(),
1057            |v| format!("{} ({})", v, dns::types::rcode_name(v)),
1058        ),
1059    ));
1060    fields.push((
1061        "qdcount",
1062        l.qdcount(buf)
1063            .map_or_else(|_| "?".into(), |v| v.to_string()),
1064    ));
1065    fields.push((
1066        "ancount",
1067        l.ancount(buf)
1068            .map_or_else(|_| "?".into(), |v| v.to_string()),
1069    ));
1070    fields.push((
1071        "nscount",
1072        l.nscount(buf)
1073            .map_or_else(|_| "?".into(), |v| v.to_string()),
1074    ));
1075    fields.push((
1076        "arcount",
1077        l.arcount(buf)
1078            .map_or_else(|_| "?".into(), |v| v.to_string()),
1079    ));
1080    // Show questions if present
1081    if let Ok(questions) = l.questions(buf) {
1082        for (i, q) in questions.iter().enumerate() {
1083            fields.push(("qd", format!("[{}] {}", i, q.summary())));
1084        }
1085    }
1086    fields
1087}
1088
1089fn ssh_show_fields(l: &SshLayer, buf: &[u8]) -> Vec<(&'static str, String)> {
1090    let mut fields = Vec::new();
1091    if l.is_version_exchange(buf) {
1092        if let Some(vs) = l.version_string(buf) {
1093            fields.push(("version_string", vs.to_string()));
1094        }
1095    } else {
1096        fields.push((
1097            "packet_length",
1098            l.packet_length(buf)
1099                .map_or_else(|_| "?".into(), |v| v.to_string()),
1100        ));
1101        fields.push((
1102            "padding_length",
1103            l.padding_length(buf)
1104                .map_or_else(|_| "?".into(), |v| v.to_string()),
1105        ));
1106        match l.message_type(buf) {
1107            Ok(Some(t)) => {
1108                fields.push((
1109                    "message_type",
1110                    format!("{} ({})", t, ssh::msg_types::name(t)),
1111                ));
1112            },
1113            Ok(None) => {},
1114            Err(_) => {
1115                fields.push(("message_type", "?".into()));
1116            },
1117        }
1118    }
1119    fields
1120}
1121
1122fn tls_show_fields(l: &TlsLayer, buf: &[u8]) -> Vec<(&'static str, String)> {
1123    let mut fields = Vec::new();
1124    fields.push((
1125        "type",
1126        l.content_type(buf).map_or_else(
1127            |_| "?".into(),
1128            |ct| format!("{} ({})", ct.as_u8(), ct.name()),
1129        ),
1130    ));
1131    fields.push((
1132        "version",
1133        l.version(buf)
1134            .map(|v| {
1135                let ver = TlsVersion(v);
1136                format!("{:#06x} ({})", v, ver.name())
1137            })
1138            .unwrap_or_else(|_| "?".into()),
1139    ));
1140    fields.push((
1141        "len",
1142        l.length(buf).map_or_else(|_| "?".into(), |v| v.to_string()),
1143    ));
1144    let frag = l.fragment(buf);
1145    if !frag.is_empty() {
1146        if frag.len() <= 16 {
1147            fields.push(("fragment", format!("[{} bytes] {:02x?}", frag.len(), frag)));
1148        } else {
1149            fields.push(("fragment", format!("[{} bytes]", frag.len())));
1150        }
1151    }
1152    fields
1153}
1154
1155fn dot11_show_fields(l: &dot11::Dot11Layer, buf: &[u8]) -> Vec<(&'static str, String)> {
1156    let mut fields = Vec::new();
1157    fields.push((
1158        "type",
1159        l.frame_type(buf).map_or_else(
1160            |_| "?".into(),
1161            |v| format!("{} ({})", v, dot11::types::frame_type::name(v)),
1162        ),
1163    ));
1164    fields.push((
1165        "subtype",
1166        l.subtype(buf)
1167            .map(|v| {
1168                let ft = l.frame_type(buf).unwrap_or(0);
1169                format!("{} ({})", v, dot11::types::subtype_name(ft, v))
1170            })
1171            .unwrap_or_else(|_| "?".into()),
1172    ));
1173    fields.push((
1174        "proto",
1175        l.protocol_version(buf)
1176            .map_or_else(|_| "?".into(), |v| v.to_string()),
1177    ));
1178    fields.push((
1179        "FCfield",
1180        l.flags(buf)
1181            .map_or_else(|_| "?".into(), |v| format!("{v:#04x}")),
1182    ));
1183    fields.push((
1184        "ID",
1185        l.duration(buf)
1186            .map_or_else(|_| "?".into(), |v| v.to_string()),
1187    ));
1188    fields.push((
1189        "addr1",
1190        l.addr1(buf).map_or_else(|_| "?".into(), |v| v.to_string()),
1191    ));
1192    fields.push((
1193        "addr2",
1194        l.addr2(buf).map_or_else(|_| "?".into(), |v| v.to_string()),
1195    ));
1196    fields.push((
1197        "addr3",
1198        l.addr3(buf).map_or_else(|_| "?".into(), |v| v.to_string()),
1199    ));
1200    fields.push((
1201        "SC",
1202        l.seq_ctrl_raw(buf)
1203            .map_or_else(|_| "?".into(), |v| format!("{v:#06x}")),
1204    ));
1205    if l.has_addr4(buf) {
1206        fields.push((
1207            "addr4",
1208            l.addr4(buf).map_or_else(|_| "?".into(), |v| v.to_string()),
1209        ));
1210    }
1211    fields
1212}
1213
1214fn dot15d4_show_fields(l: &dot15d4::Dot15d4Layer, buf: &[u8]) -> Vec<(&'static str, String)> {
1215    let mut fields = Vec::new();
1216    // Frame type with name
1217    let ft = l.fcf_frametype(buf).unwrap_or(0);
1218    fields.push((
1219        "fcf_frametype",
1220        format!("{} ({})", ft, dot15d4::types::frame_type_name(ft)),
1221    ));
1222    // FCF flags
1223    fields.push((
1224        "fcf_security",
1225        l.fcf_security(buf)
1226            .map_or_else(|_| "?".into(), |v| v.to_string()),
1227    ));
1228    fields.push((
1229        "fcf_pending",
1230        l.fcf_pending(buf)
1231            .map_or_else(|_| "?".into(), |v| v.to_string()),
1232    ));
1233    fields.push((
1234        "fcf_ackreq",
1235        l.fcf_ackreq(buf)
1236            .map_or_else(|_| "?".into(), |v| v.to_string()),
1237    ));
1238    fields.push((
1239        "fcf_panidcompress",
1240        l.fcf_panidcompress(buf)
1241            .map_or_else(|_| "?".into(), |v| v.to_string()),
1242    ));
1243    // Address modes with names
1244    let dam = l.fcf_destaddrmode(buf).unwrap_or(0);
1245    fields.push((
1246        "fcf_destaddrmode",
1247        format!("{} ({})", dam, dot15d4::types::addr_mode_name(dam)),
1248    ));
1249    fields.push((
1250        "fcf_framever",
1251        l.fcf_framever(buf)
1252            .map_or_else(|_| "?".into(), |v| v.to_string()),
1253    ));
1254    let sam = l.fcf_srcaddrmode(buf).unwrap_or(0);
1255    fields.push((
1256        "fcf_srcaddrmode",
1257        format!("{} ({})", sam, dot15d4::types::addr_mode_name(sam)),
1258    ));
1259    // Sequence number
1260    fields.push((
1261        "seqnum",
1262        l.seqnum(buf).map_or_else(|_| "?".into(), |v| v.to_string()),
1263    ));
1264    // Conditional addressing fields
1265    if let Ok(Some(panid)) = l.dest_panid(buf) {
1266        fields.push(("dest_panid", format!("{panid:#06x}")));
1267    }
1268    if let Ok(Some(addr)) = l.dest_addr_short(buf) {
1269        fields.push(("dest_addr", format!("{addr:#06x}")));
1270    }
1271    if let Ok(Some(addr)) = l.dest_addr_long(buf) {
1272        fields.push(("dest_addr", format!("{addr:#018x}")));
1273    }
1274    if let Ok(Some(panid)) = l.src_panid(buf) {
1275        fields.push(("src_panid", format!("{panid:#06x}")));
1276    }
1277    if let Ok(Some(addr)) = l.src_addr_short(buf) {
1278        fields.push(("src_addr", format!("{addr:#06x}")));
1279    }
1280    if let Ok(Some(addr)) = l.src_addr_long(buf) {
1281        fields.push(("src_addr", format!("{addr:#018x}")));
1282    }
1283    fields
1284}
1285
1286fn dot15d4_fcs_show_fields(
1287    l: &dot15d4::Dot15d4FcsLayer,
1288    buf: &[u8],
1289) -> Vec<(&'static str, String)> {
1290    let inner = dot15d4::Dot15d4Layer::new(l.index.start, l.index.end.saturating_sub(2));
1291    let mut fields = dot15d4_show_fields(&inner, buf);
1292    // Show FCS with verification status
1293    let slice = l.index.slice(buf);
1294    if slice.len() >= 2 {
1295        let fcs_bytes = &slice[slice.len() - 2..];
1296        let fcs = u16::from_le_bytes([fcs_bytes[0], fcs_bytes[1]]);
1297        let verified = l.verify_fcs(buf).unwrap_or(false);
1298        let status = if verified { "ok" } else { "INVALID" };
1299        fields.push(("fcs", format!("{fcs:#06x} ({status})")));
1300    }
1301    fields
1302}
1303
1304fn http_show_fields(l: &http::HttpLayer, buf: &[u8]) -> Vec<(&'static str, String)> {
1305    let mut fields = Vec::new();
1306    if l.is_request(buf) {
1307        fields.push(("method", l.method(buf).unwrap_or("?").to_string()));
1308        fields.push(("uri", l.uri(buf).unwrap_or("?").to_string()));
1309        fields.push(("version", l.http_version(buf).unwrap_or("?").to_string()));
1310    } else if l.is_response(buf) {
1311        fields.push(("version", l.http_version(buf).unwrap_or("?").to_string()));
1312        fields.push((
1313            "status_code",
1314            l.status_code(buf)
1315                .map_or_else(|| "?".into(), |c| c.to_string()),
1316        ));
1317        fields.push(("reason", l.reason(buf).unwrap_or("?").to_string()));
1318    }
1319    fields
1320}
1321
1322fn http2_show_fields(l: &http2::Http2Layer, buf: &[u8]) -> Vec<(&'static str, String)> {
1323    let mut fields = Vec::new();
1324    if l.has_preface {
1325        fields.push(("preface", "true".to_string()));
1326    }
1327    if let Some(frame) = l.first_frame(buf) {
1328        fields.push((
1329            "frame_type",
1330            format!("{} ({})", frame.frame_type.as_u8(), frame.frame_type.name()),
1331        ));
1332        fields.push(("flags", format!("{:#04x}", frame.flags)));
1333        fields.push(("stream_id", frame.stream_id.to_string()));
1334        fields.push(("length", frame.length.to_string()));
1335    }
1336    fields
1337}
1338
1339fn quic_show_fields(l: &quic::QuicLayer, buf: &[u8]) -> Vec<(&'static str, String)> {
1340    let mut fields = Vec::new();
1341    fields.push((
1342        "header_form",
1343        if l.is_long_header(buf) {
1344            "long".to_string()
1345        } else {
1346            "short".to_string()
1347        },
1348    ));
1349    if let Some(pt) = l.packet_type(buf) {
1350        fields.push(("packet_type", pt.name().to_string()));
1351    }
1352    if let Some(ver) = l.version(buf) {
1353        fields.push(("version", format!("{ver:#010x}")));
1354    }
1355    fields
1356}
1357
1358fn l2tp_show_fields(l: &l2tp::L2tpLayer, buf: &[u8]) -> Vec<(&'static str, String)> {
1359    let mut fields = Vec::new();
1360    fields.push((
1361        "flags",
1362        l.flags_word(buf)
1363            .map_or_else(|_| "?".into(), |v| format!("{v:#06x}")),
1364    ));
1365    fields.push((
1366        "version",
1367        l.version(buf)
1368            .map_or_else(|_| "?".into(), |v| v.to_string()),
1369    ));
1370    fields.push((
1371        "msg_type",
1372        l.msg_type(buf)
1373            .map(|v| {
1374                if v == 0 {
1375                    "data".to_string()
1376                } else {
1377                    "control".to_string()
1378                }
1379            })
1380            .unwrap_or_else(|_| "?".into()),
1381    ));
1382    if let Ok(Some(length)) = l.length(buf) {
1383        fields.push(("length", length.to_string()));
1384    }
1385    fields.push((
1386        "tunnel_id",
1387        l.tunnel_id(buf)
1388            .map_or_else(|_| "?".into(), |v| v.to_string()),
1389    ));
1390    fields.push((
1391        "session_id",
1392        l.session_id(buf)
1393            .map_or_else(|_| "?".into(), |v| v.to_string()),
1394    ));
1395    if let Ok(Some(ns)) = l.ns(buf) {
1396        fields.push(("ns", ns.to_string()));
1397    }
1398    if let Ok(Some(nr)) = l.nr(buf) {
1399        fields.push(("nr", nr.to_string()));
1400    }
1401    fields
1402}
1403
1404fn mqtt_show_fields(l: &mqtt::MqttLayer, buf: &[u8]) -> Vec<(&'static str, String)> {
1405    let mut fields = Vec::new();
1406    fields.push((
1407        "msg_type",
1408        l.msg_type(buf).map_or_else(
1409            |_| "?".into(),
1410            |v| format!("{} ({})", v, mqtt::message_type_name(v)),
1411        ),
1412    ));
1413    fields.push((
1414        "dup",
1415        l.dup(buf).map_or_else(|_| "?".into(), |v| v.to_string()),
1416    ));
1417    fields.push((
1418        "qos",
1419        l.qos(buf).map_or_else(|_| "?".into(), |v| v.to_string()),
1420    ));
1421    fields.push((
1422        "retain",
1423        l.retain(buf).map_or_else(|_| "?".into(), |v| v.to_string()),
1424    ));
1425    fields.push((
1426        "remaining_length",
1427        l.remaining_length(buf)
1428            .map_or_else(|_| "?".into(), |v| v.to_string()),
1429    ));
1430    if let Ok(mt) = l.msg_type(buf) {
1431        if mt == mqtt::PUBLISH {
1432            if let Ok(topic) = l.topic(buf) {
1433                fields.push(("topic", topic));
1434            }
1435        } else if mt == mqtt::CONNECT {
1436            if let Ok(name) = l.proto_name(buf) {
1437                fields.push(("proto_name", name));
1438            }
1439            if let Ok(level) = l.proto_level(buf) {
1440                fields.push(("proto_level", level.to_string()));
1441            }
1442            if let Ok(klive) = l.klive(buf) {
1443                fields.push(("klive", klive.to_string()));
1444            }
1445            if let Ok(cid) = l.client_id(buf) {
1446                fields.push(("client_id", cid));
1447            }
1448        } else if mt == mqtt::CONNACK
1449            && let Ok(rc) = l.retcode(buf)
1450        {
1451            fields.push(("retcode", rc.to_string()));
1452        }
1453    }
1454    fields
1455}
1456
1457fn mqttsn_show_fields(l: &mqttsn::MqttSnLayer, buf: &[u8]) -> Vec<(&'static str, String)> {
1458    let mut fields = Vec::new();
1459    fields.push((
1460        "length",
1461        l.packet_length(buf)
1462            .map_or_else(|_| "?".into(), |v| v.to_string()),
1463    ));
1464    let mt = l.msg_type(buf).unwrap_or(0xFF);
1465    fields.push((
1466        "type",
1467        format!("{} ({})", mt, mqttsn::message_type_name(mt)),
1468    ));
1469    if let Ok(v) = l.gw_id(buf) {
1470        fields.push(("gw_id", format!("{v:#04x}")));
1471    }
1472    if let Ok(v) = l.duration(buf) {
1473        fields.push(("duration", v.to_string()));
1474    }
1475    if let Ok(v) = l.return_code(buf) {
1476        fields.push(("return_code", v.to_string()));
1477    }
1478    if let Ok(v) = l.tid(buf) {
1479        fields.push(("tid", format!("{v:#06x}")));
1480    }
1481    if let Ok(v) = l.mid(buf) {
1482        fields.push(("mid", format!("{v:#06x}")));
1483    }
1484    fields
1485}
1486
1487fn modbus_show_fields(l: &modbus::ModbusLayer, buf: &[u8]) -> Vec<(&'static str, String)> {
1488    let mut fields = Vec::new();
1489    fields.push((
1490        "trans_id",
1491        l.trans_id(buf)
1492            .map_or_else(|_| "?".into(), |v| v.to_string()),
1493    ));
1494    fields.push((
1495        "proto_id",
1496        l.proto_id(buf)
1497            .map_or_else(|_| "?".into(), |v| format!("{v:#06x}")),
1498    ));
1499    fields.push((
1500        "length",
1501        l.length(buf).map_or_else(|_| "?".into(), |v| v.to_string()),
1502    ));
1503    fields.push((
1504        "unit_id",
1505        l.unit_id(buf)
1506            .map_or_else(|_| "?".into(), |v| format!("{v:#04x}")),
1507    ));
1508    let fc = l.func_code(buf).unwrap_or(0);
1509    fields.push((
1510        "func_code",
1511        format!("{:#04x} ({})", fc, modbus::func_code_name(fc)),
1512    ));
1513    if l.is_error(buf) {
1514        fields.push((
1515            "except_code",
1516            l.except_code(buf).map_or_else(
1517                |_| "?".into(),
1518                |v| format!("{} ({})", v, modbus::except_code_name(v)),
1519            ),
1520        ));
1521    }
1522    fields
1523}
1524
1525fn zwave_show_fields(l: &zwave::ZWaveLayer, buf: &[u8]) -> Vec<(&'static str, String)> {
1526    let mut fields = Vec::new();
1527    fields.push((
1528        "home_id",
1529        l.home_id(buf)
1530            .map_or_else(|_| "?".into(), |v| format!("{v:#010x}")),
1531    ));
1532    fields.push((
1533        "src",
1534        l.src(buf).map_or_else(|_| "?".into(), |v| v.to_string()),
1535    ));
1536    fields.push((
1537        "dst",
1538        l.dst(buf).map_or_else(|_| "?".into(), |v| v.to_string()),
1539    ));
1540    fields.push((
1541        "routed",
1542        l.routed(buf).map_or_else(|_| "?".into(), |v| v.to_string()),
1543    ));
1544    fields.push((
1545        "ackreq",
1546        l.ackreq(buf).map_or_else(|_| "?".into(), |v| v.to_string()),
1547    ));
1548    fields.push((
1549        "lowpower",
1550        l.lowpower(buf)
1551            .map_or_else(|_| "?".into(), |v| v.to_string()),
1552    ));
1553    fields.push((
1554        "speedmodified",
1555        l.speedmodified(buf)
1556            .map_or_else(|_| "?".into(), |v| v.to_string()),
1557    ));
1558    fields.push((
1559        "headertype",
1560        l.headertype(buf)
1561            .map_or_else(|_| "?".into(), |v| format!("{v:#04x}")),
1562    ));
1563    fields.push((
1564        "beam_control",
1565        l.beam_control(buf)
1566            .map_or_else(|_| "?".into(), |v| v.to_string()),
1567    ));
1568    fields.push((
1569        "seqn",
1570        l.seqn(buf).map_or_else(|_| "?".into(), |v| v.to_string()),
1571    ));
1572    fields.push((
1573        "length",
1574        l.length(buf).map_or_else(|_| "?".into(), |v| v.to_string()),
1575    ));
1576    if !l.is_ack(buf) {
1577        fields.push((
1578            "cmd_class",
1579            l.cmd_class(buf).map_or_else(
1580                |_| "?".into(),
1581                |v| format!("{:#04x} ({})", v, zwave::cmd_class_name(v)),
1582            ),
1583        ));
1584        if let Ok(cmd) = l.cmd(buf) {
1585            fields.push(("cmd", format!("{cmd:#04x}")));
1586        }
1587    }
1588    fields.push((
1589        "crc",
1590        l.crc(buf)
1591            .map_or_else(|_| "?".into(), |v| format!("{v:#04x}")),
1592    ));
1593    fields
1594}
1595
1596fn dhcp_show_fields(l: &dhcp::DhcpLayer, buf: &[u8]) -> Vec<(&'static str, String)> {
1597    let mut fields = Vec::new();
1598    fields.push((
1599        "op",
1600        l.op(buf).map_or_else(|_| "?".into(), |v| v.to_string()),
1601    ));
1602    fields.push((
1603        "htype",
1604        l.htype(buf).map_or_else(|_| "?".into(), |v| v.to_string()),
1605    ));
1606    fields.push((
1607        "hlen",
1608        l.hlen(buf).map_or_else(|_| "?".into(), |v| v.to_string()),
1609    ));
1610    fields.push((
1611        "hops",
1612        l.hops(buf).map_or_else(|_| "?".into(), |v| v.to_string()),
1613    ));
1614    fields.push((
1615        "xid",
1616        l.xid(buf)
1617            .map_or_else(|_| "?".into(), |v| format!("{v:#010x}")),
1618    ));
1619    fields.push((
1620        "secs",
1621        l.secs(buf).map_or_else(|_| "?".into(), |v| v.to_string()),
1622    ));
1623    fields.push((
1624        "flags",
1625        l.flags(buf)
1626            .map_or_else(|_| "?".into(), |v| format!("{v:#06x}")),
1627    ));
1628    fields.push((
1629        "ciaddr",
1630        l.ciaddr(buf).map_or_else(|_| "?".into(), |v| v.to_string()),
1631    ));
1632    fields.push((
1633        "yiaddr",
1634        l.yiaddr(buf).map_or_else(|_| "?".into(), |v| v.to_string()),
1635    ));
1636    fields.push((
1637        "siaddr",
1638        l.siaddr(buf).map_or_else(|_| "?".into(), |v| v.to_string()),
1639    ));
1640    fields.push((
1641        "giaddr",
1642        l.giaddr(buf).map_or_else(|_| "?".into(), |v| v.to_string()),
1643    ));
1644    fields.push((
1645        "chaddr",
1646        l.chaddr(buf).map_or_else(
1647            |_| "?".into(),
1648            |mac| {
1649                format!(
1650                    "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
1651                    mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]
1652                )
1653            },
1654        ),
1655    ));
1656    if let Some(mt) = l.msg_type(buf) {
1657        let name = match mt {
1658            1 => "Discover",
1659            2 => "Offer",
1660            3 => "Request",
1661            4 => "Decline",
1662            5 => "ACK",
1663            6 => "NAK",
1664            7 => "Release",
1665            8 => "Inform",
1666            _ => "Unknown",
1667        };
1668        fields.push(("msg_type", format!("{mt} ({name})")));
1669    }
1670    if let Some(sid) = l.server_id(buf) {
1671        fields.push(("server_id", sid.to_string()));
1672    }
1673    if let Some(rip) = l.requested_ip(buf) {
1674        fields.push(("requested_ip", rip.to_string()));
1675    }
1676    if let Some(lt) = l.lease_time(buf) {
1677        fields.push(("lease_time", lt.to_string()));
1678    }
1679    if let Some(sm) = l.subnet_mask(buf) {
1680        fields.push(("subnet_mask", sm.to_string()));
1681    }
1682    if let Some(r) = l.router(buf) {
1683        fields.push(("router", r.to_string()));
1684    }
1685    let dns_servers = l.dns(buf);
1686    if !dns_servers.is_empty() {
1687        let s = dns_servers
1688            .iter()
1689            .map(|ip| ip.to_string())
1690            .collect::<Vec<_>>()
1691            .join(", ");
1692        fields.push(("dns", s));
1693    }
1694    fields
1695}
1696
1697pub use dns::DnsLayer;
1698
1699// ============================================================================
1700// LayerDispatch implementations (auto-dispatched by enum_dispatch)
1701// ============================================================================
1702
1703impl_layer_dispatch!(EthernetLayer, show = ethernet_show_fields);
1704impl_layer_dispatch!(
1705    Dot3Layer,
1706    show = dot3_show_fields,
1707    inherent,
1708    kind = LayerKind::Dot3,
1709    header_len = ethernet::ETHERNET_HEADER_LEN
1710);
1711impl_layer_dispatch!(ArpLayer, show = arp_show_fields);
1712impl_layer_dispatch!(Ipv4Layer, show = ipv4_show_fields);
1713impl_layer_dispatch!(Ipv6Layer, show = ipv6_show_fields);
1714impl_layer_dispatch!(IcmpLayer, show = icmp_show_fields);
1715impl_layer_dispatch!(Icmpv6Layer, show = icmpv6_show_fields);
1716impl_layer_dispatch!(TcpLayer, show = tcp_show_fields);
1717impl_layer_dispatch!(UdpLayer, show = udp_show_fields);
1718impl_layer_dispatch!(DnsLayer, show = dns_show_fields);
1719impl_layer_dispatch!(SshLayer, show = ssh_show_fields);
1720impl_layer_dispatch!(TlsLayer, show = tls_show_fields);
1721impl_layer_dispatch!(dot15d4::Dot15d4Layer, show = dot15d4_show_fields);
1722impl_layer_dispatch!(dot15d4::Dot15d4FcsLayer, show = dot15d4_fcs_show_fields);
1723impl_layer_dispatch!(dot11::Dot11Layer, show = dot11_show_fields);
1724impl_layer_dispatch!(HttpLayer, show = http_show_fields, readonly);
1725impl_layer_dispatch!(Http2Layer, show = http2_show_fields, readonly);
1726impl_layer_dispatch!(quic::QuicLayer, show = quic_show_fields);
1727impl_layer_dispatch!(l2tp::L2tpLayer, show = l2tp_show_fields);
1728impl_layer_dispatch!(mqtt::MqttLayer, show = mqtt_show_fields);
1729impl_layer_dispatch!(mqttsn::MqttSnLayer, show = mqttsn_show_fields);
1730impl_layer_dispatch!(modbus::ModbusLayer, show = modbus_show_fields);
1731impl_layer_dispatch!(zwave::ZWaveLayer, show = zwave_show_fields);
1732impl_layer_dispatch!(ftp::FtpLayer, show = ftp::ftp_show_fields, readonly);
1733impl_layer_dispatch!(tftp::TftpLayer, show = tftp::tftp_show_fields, readonly);
1734impl_layer_dispatch!(smtp::SmtpLayer, show = smtp::smtp_show_fields, readonly);
1735impl_layer_dispatch!(pop3::Pop3Layer, show = pop3::pop3_show_fields, readonly);
1736impl_layer_dispatch!(imap::ImapLayer, show = imap::imap_show_fields, readonly);
1737impl_layer_dispatch!(dhcp::DhcpLayer, show = dhcp_show_fields);
1738// RawLayer: header_len depends on buf, so we need a custom impl
1739impl LayerDispatch for RawLayer {
1740    #[inline]
1741    fn dispatch_kind(&self) -> LayerKind {
1742        LayerKind::Raw
1743    }
1744    #[inline]
1745    fn dispatch_index(&self) -> &LayerIndex {
1746        &self.index
1747    }
1748    #[inline]
1749    fn dispatch_summary(&self, buf: &[u8]) -> String {
1750        self.summary(buf)
1751    }
1752    #[inline]
1753    fn dispatch_header_len(&self, buf: &[u8]) -> usize {
1754        self.header_len(buf)
1755    }
1756    #[inline]
1757    fn dispatch_hashret(&self, buf: &[u8]) -> Vec<u8> {
1758        self.hashret(buf)
1759    }
1760    #[inline]
1761    fn dispatch_field_names(&self) -> &'static [&'static str] {
1762        RawLayer::field_names()
1763    }
1764    #[inline]
1765    fn dispatch_get_field(&self, buf: &[u8], name: &str) -> Option<Result<FieldValue, FieldError>> {
1766        self.get_field(buf, name)
1767    }
1768    #[inline]
1769    fn dispatch_set_field(
1770        &self,
1771        buf: &mut [u8],
1772        name: &str,
1773        value: FieldValue,
1774    ) -> Option<Result<(), FieldError>> {
1775        self.set_field(buf, name, value)
1776    }
1777    #[inline]
1778    fn dispatch_show_fields(&self, buf: &[u8]) -> Vec<(&'static str, String)> {
1779        raw::raw_show_fields(self, buf)
1780    }
1781}
1782
1783/// `EtherType` constants
1784pub mod ethertype {
1785    use crate::LayerKind;
1786
1787    pub const IPV4: u16 = 0x0800;
1788    pub const ARP: u16 = 0x0806;
1789    pub const IPV6: u16 = 0x86DD;
1790    pub const VLAN: u16 = 0x8100;
1791    pub const DOT1AD: u16 = 0x88A8;
1792    pub const DOT1AH: u16 = 0x88E7;
1793    pub const MACSEC: u16 = 0x88E5;
1794    pub const LOOPBACK: u16 = 0x9000;
1795
1796    #[must_use]
1797    pub fn name(t: u16) -> &'static str {
1798        match t {
1799            IPV4 => "IPv4",
1800            ARP => "ARP",
1801            IPV6 => "IPv6",
1802            VLAN => "802.1Q",
1803            DOT1AD => "802.1AD",
1804            DOT1AH => "802.1AH",
1805            MACSEC => "MACsec",
1806            LOOPBACK => "Loopback",
1807            _ => "Unknown",
1808        }
1809    }
1810
1811    #[must_use]
1812    pub fn to_layer_kind(t: u16) -> Option<LayerKind> {
1813        match t {
1814            IPV4 => Some(LayerKind::Ipv4),
1815            ARP => Some(LayerKind::Arp),
1816            IPV6 => Some(LayerKind::Ipv6),
1817            VLAN => Some(LayerKind::Dot1Q),
1818            DOT1AD => Some(LayerKind::Dot1AD),
1819            DOT1AH => Some(LayerKind::Dot1AH),
1820            _ => None,
1821        }
1822    }
1823
1824    #[must_use]
1825    pub fn from_layer_kind(kind: LayerKind) -> Option<u16> {
1826        match kind {
1827            LayerKind::Ipv4 => Some(IPV4),
1828            LayerKind::Arp => Some(ARP),
1829            LayerKind::Ipv6 => Some(IPV6),
1830            LayerKind::Dot1Q => Some(VLAN),
1831            LayerKind::Dot1AD => Some(DOT1AD),
1832            LayerKind::Dot1AH => Some(DOT1AH),
1833            _ => None,
1834        }
1835    }
1836}
1837
1838/// IP protocol numbers
1839pub mod ip_protocol {
1840    pub use crate::layer::ipv4::protocol::*;
1841}
1842
1843#[cfg(test)]
1844mod tests {
1845    use super::*;
1846
1847    #[test]
1848    fn test_layer_kind() {
1849        assert_eq!(LayerKind::Ethernet.name(), "Ethernet");
1850        assert_eq!(LayerKind::Arp.min_header_size(), 28);
1851        assert!(LayerKind::Ethernet.is_link_layer());
1852        assert!(LayerKind::Ipv4.is_network_layer());
1853        assert!(LayerKind::Tcp.is_transport_layer());
1854    }
1855
1856    #[test]
1857    fn test_layer_index() {
1858        let idx = LayerIndex::new(LayerKind::Ethernet, 0, 14);
1859        assert_eq!(idx.len(), 14);
1860        assert_eq!(idx.range(), 0..14);
1861
1862        let buf = vec![0u8; 100];
1863        assert_eq!(idx.slice(&buf).len(), 14);
1864        assert_eq!(idx.payload(&buf).len(), 86);
1865    }
1866
1867    #[test]
1868    fn test_ethertype_conversions() {
1869        assert_eq!(ethertype::to_layer_kind(0x0800), Some(LayerKind::Ipv4));
1870        assert_eq!(ethertype::from_layer_kind(LayerKind::Arp), Some(0x0806));
1871    }
1872}