Skip to main content

packet_strata/packet/tunnel/
l2tp.rs

1//! L2TP (Layer 2 Tunneling Protocol) parser
2//!
3//! This module implements parsing for L2TP as defined in:
4//! - RFC 2661: Layer Two Tunneling Protocol "L2TP" (L2TPv2)
5//! - RFC 3931: Layer Two Tunneling Protocol - Version 3 (L2TPv3)
6//!
7//! L2TP is used to tunnel PPP sessions over an IP network. L2TPv2 is widely
8//! deployed for VPN access, while L2TPv3 extends the protocol for tunneling
9//! any Layer 2 protocol.
10//!
11//! # L2TPv2 Header Format (RFC 2661)
12//!
13//! ```text
14//!  0                   1                   2                   3
15//!  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
16//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
17//! |T|L|x|x|S|x|O|P|x|x|x|x|  Ver  |          Length (opt)         |
18//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
19//! |           Tunnel ID           |           Session ID          |
20//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
21//! |             Ns (opt)          |             Nr (opt)          |
22//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
23//! |      Offset Size (opt)        |    Offset pad... (opt)        |
24//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
25//! ```
26//!
27//! # L2TPv3 Header Format (RFC 3931)
28//!
29//! L2TPv3 over UDP:
30//! ```text
31//!  0                   1                   2                   3
32//!  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
33//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
34//! |T|L|x|x|S|x|O|P|x|x|x|x|  Ver  |          Length (opt)         |
35//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
36//! |                 Control Connection ID (opt)                   |
37//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
38//! |             Ns (opt)          |             Nr (opt)          |
39//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
40//! ```
41//!
42//! L2TPv3 Data Session Header:
43//! ```text
44//!  0                   1                   2                   3
45//!  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
46//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
47//! |                      Session ID (32 bits)                     |
48//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
49//! |               Cookie (optional, 0, 32, or 64 bits)            |
50//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
51//! ```
52//!
53//! # Ports
54//!
55//! - L2TP: UDP port 1701 (both L2TPv2 and L2TPv3 control)
56//! - L2TPv3 can also use IP protocol 115 for data sessions
57//!
58//! # Examples
59//!
60//! ## Basic L2TPv2 data parsing
61//!
62//! ```
63//! use packet_strata::packet::tunnel::l2tp::L2tpv2Header;
64//! use packet_strata::packet::HeaderParser;
65//!
66//! // L2TPv2 data packet (minimal header)
67//! let packet = vec![
68//!     0x00, 0x02,  // flags: T=0 (data), L=0, S=0, O=0, P=0, Ver=2
69//!     0x00, 0x01,  // Tunnel ID: 1
70//!     0x00, 0x02,  // Session ID: 2
71//!     // PPP payload follows...
72//!     0xFF, 0x03, 0x00, 0x21,
73//! ];
74//!
75//! let (header, payload) = L2tpv2Header::from_bytes(&packet).unwrap();
76//! assert_eq!(header.version(), 2);
77//! assert!(!header.is_control());
78//! assert_eq!(header.tunnel_id(), 1);
79//! assert_eq!(header.session_id(), 2);
80//! ```
81//!
82//! ## L2TPv2 control message parsing
83//!
84//! ```
85//! use packet_strata::packet::tunnel::l2tp::L2tpv2Header;
86//! use packet_strata::packet::HeaderParser;
87//!
88//! // L2TPv2 control message with length and sequence
89//! let packet = vec![
90//!     0xC8, 0x02,  // flags: T=1, L=1, S=1, Ver=2
91//!     0x00, 0x14,  // Length: 20 bytes
92//!     0x00, 0x01,  // Tunnel ID: 1
93//!     0x00, 0x00,  // Session ID: 0 (control)
94//!     0x00, 0x01,  // Ns: 1
95//!     0x00, 0x00,  // Nr: 0
96//!     // AVPs follow...
97//!     0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
98//! ];
99//!
100//! let (header, payload) = L2tpv2Header::from_bytes(&packet).unwrap();
101//! assert!(header.is_control());
102//! assert!(header.has_length());
103//! assert!(header.has_sequence());
104//! assert_eq!(header.ns(), Some(1));
105//! assert_eq!(header.nr(), Some(0));
106//! ```
107
108use std::fmt::{self, Formatter};
109
110use zerocopy::byteorder::{BigEndian, U16, U32};
111use zerocopy::{FromBytes, IntoBytes, Unaligned};
112
113use crate::packet::{HeaderParser, PacketHeader, PacketHeaderError};
114
115/// L2TP standard port (UDP)
116pub const L2TP_PORT: u16 = 1701;
117
118/// L2TPv3 IP protocol number
119pub const L2TPV3_IP_PROTO: u8 = 115;
120
121/// Check if port is L2TP
122#[inline]
123pub fn is_l2tp_port(port: u16) -> bool {
124    port == L2TP_PORT
125}
126
127/// Check if IP protocol is L2TPv3
128#[inline]
129pub fn is_l2tpv3_proto(proto: u8) -> bool {
130    proto == L2TPV3_IP_PROTO
131}
132
133/// L2TPv2 Message Types (from RFC 2661)
134#[derive(Debug, Clone, Copy, PartialEq, Eq)]
135pub enum L2tpv2MessageType {
136    /// Start-Control-Connection-Request
137    Sccrq,
138    /// Start-Control-Connection-Reply
139    Sccrp,
140    /// Start-Control-Connection-Connected
141    Scccn,
142    /// Stop-Control-Connection-Notification
143    StopCcn,
144    /// Hello (keep-alive)
145    Hello,
146    /// Outgoing-Call-Request
147    Ocrq,
148    /// Outgoing-Call-Reply
149    Ocrp,
150    /// Outgoing-Call-Connected
151    Occn,
152    /// Incoming-Call-Request
153    Icrq,
154    /// Incoming-Call-Reply
155    Icrp,
156    /// Incoming-Call-Connected
157    Iccn,
158    /// Call-Disconnect-Notify
159    Cdn,
160    /// WAN-Error-Notify
161    Wen,
162    /// Set-Link-Info
163    Sli,
164    /// Zero-Length Body (ZLB) ACK
165    Zlb,
166    /// Unknown message type
167    Unknown(u16),
168}
169
170impl From<u16> for L2tpv2MessageType {
171    fn from(value: u16) -> Self {
172        match value {
173            1 => L2tpv2MessageType::Sccrq,
174            2 => L2tpv2MessageType::Sccrp,
175            3 => L2tpv2MessageType::Scccn,
176            4 => L2tpv2MessageType::StopCcn,
177            6 => L2tpv2MessageType::Hello,
178            7 => L2tpv2MessageType::Ocrq,
179            8 => L2tpv2MessageType::Ocrp,
180            9 => L2tpv2MessageType::Occn,
181            10 => L2tpv2MessageType::Icrq,
182            11 => L2tpv2MessageType::Icrp,
183            12 => L2tpv2MessageType::Iccn,
184            14 => L2tpv2MessageType::Cdn,
185            15 => L2tpv2MessageType::Wen,
186            16 => L2tpv2MessageType::Sli,
187            0 => L2tpv2MessageType::Zlb,
188            v => L2tpv2MessageType::Unknown(v),
189        }
190    }
191}
192
193impl fmt::Display for L2tpv2MessageType {
194    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
195        match self {
196            L2tpv2MessageType::Sccrq => write!(f, "SCCRQ"),
197            L2tpv2MessageType::Sccrp => write!(f, "SCCRP"),
198            L2tpv2MessageType::Scccn => write!(f, "SCCCN"),
199            L2tpv2MessageType::StopCcn => write!(f, "StopCCN"),
200            L2tpv2MessageType::Hello => write!(f, "Hello"),
201            L2tpv2MessageType::Ocrq => write!(f, "OCRQ"),
202            L2tpv2MessageType::Ocrp => write!(f, "OCRP"),
203            L2tpv2MessageType::Occn => write!(f, "OCCN"),
204            L2tpv2MessageType::Icrq => write!(f, "ICRQ"),
205            L2tpv2MessageType::Icrp => write!(f, "ICRP"),
206            L2tpv2MessageType::Iccn => write!(f, "ICCN"),
207            L2tpv2MessageType::Cdn => write!(f, "CDN"),
208            L2tpv2MessageType::Wen => write!(f, "WEN"),
209            L2tpv2MessageType::Sli => write!(f, "SLI"),
210            L2tpv2MessageType::Zlb => write!(f, "ZLB"),
211            L2tpv2MessageType::Unknown(v) => write!(f, "Unknown({})", v),
212        }
213    }
214}
215
216/// L2TPv3 Message Types (from RFC 3931)
217#[derive(Debug, Clone, Copy, PartialEq, Eq)]
218pub enum L2tpv3MessageType {
219    /// Start-Control-Connection-Request
220    Sccrq,
221    /// Start-Control-Connection-Reply
222    Sccrp,
223    /// Start-Control-Connection-Connected
224    Scccn,
225    /// Stop-Control-Connection-Notification
226    StopCcn,
227    /// Hello (keep-alive)
228    Hello,
229    /// Incoming-Call-Request
230    Icrq,
231    /// Incoming-Call-Reply
232    Icrp,
233    /// Incoming-Call-Connected
234    Iccn,
235    /// Outgoing-Call-Request
236    Ocrq,
237    /// Outgoing-Call-Reply
238    Ocrp,
239    /// Outgoing-Call-Connected
240    Occn,
241    /// Call-Disconnect-Notify
242    Cdn,
243    /// Set-Link-Info
244    Sli,
245    /// Explicit Acknowledgement
246    Ack,
247    /// Zero-Length Body
248    Zlb,
249    /// Unknown message type
250    Unknown(u16),
251}
252
253impl From<u16> for L2tpv3MessageType {
254    fn from(value: u16) -> Self {
255        match value {
256            1 => L2tpv3MessageType::Sccrq,
257            2 => L2tpv3MessageType::Sccrp,
258            3 => L2tpv3MessageType::Scccn,
259            4 => L2tpv3MessageType::StopCcn,
260            6 => L2tpv3MessageType::Hello,
261            7 => L2tpv3MessageType::Ocrq,
262            8 => L2tpv3MessageType::Ocrp,
263            9 => L2tpv3MessageType::Occn,
264            10 => L2tpv3MessageType::Icrq,
265            11 => L2tpv3MessageType::Icrp,
266            12 => L2tpv3MessageType::Iccn,
267            14 => L2tpv3MessageType::Cdn,
268            16 => L2tpv3MessageType::Sli,
269            20 => L2tpv3MessageType::Ack,
270            0 => L2tpv3MessageType::Zlb,
271            v => L2tpv3MessageType::Unknown(v),
272        }
273    }
274}
275
276impl fmt::Display for L2tpv3MessageType {
277    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
278        match self {
279            L2tpv3MessageType::Sccrq => write!(f, "SCCRQ"),
280            L2tpv3MessageType::Sccrp => write!(f, "SCCRP"),
281            L2tpv3MessageType::Scccn => write!(f, "SCCCN"),
282            L2tpv3MessageType::StopCcn => write!(f, "StopCCN"),
283            L2tpv3MessageType::Hello => write!(f, "Hello"),
284            L2tpv3MessageType::Icrq => write!(f, "ICRQ"),
285            L2tpv3MessageType::Icrp => write!(f, "ICRP"),
286            L2tpv3MessageType::Iccn => write!(f, "ICCN"),
287            L2tpv3MessageType::Ocrq => write!(f, "OCRQ"),
288            L2tpv3MessageType::Ocrp => write!(f, "OCRP"),
289            L2tpv3MessageType::Occn => write!(f, "OCCN"),
290            L2tpv3MessageType::Cdn => write!(f, "CDN"),
291            L2tpv3MessageType::Sli => write!(f, "SLI"),
292            L2tpv3MessageType::Ack => write!(f, "ACK"),
293            L2tpv3MessageType::Zlb => write!(f, "ZLB"),
294            L2tpv3MessageType::Unknown(v) => write!(f, "Unknown({})", v),
295        }
296    }
297}
298
299/// L2TP AVP (Attribute Value Pair) Types
300#[derive(Debug, Clone, Copy, PartialEq, Eq)]
301pub enum L2tpAvpType {
302    /// Message Type AVP
303    MessageType,
304    /// Result Code AVP
305    ResultCode,
306    /// Protocol Version AVP
307    ProtocolVersion,
308    /// Framing Capabilities AVP
309    FramingCapabilities,
310    /// Bearer Capabilities AVP
311    BearerCapabilities,
312    /// Tie Breaker AVP
313    TieBreaker,
314    /// Firmware Revision AVP
315    FirmwareRevision,
316    /// Host Name AVP
317    HostName,
318    /// Vendor Name AVP
319    VendorName,
320    /// Assigned Tunnel ID AVP
321    AssignedTunnelId,
322    /// Receive Window Size AVP
323    ReceiveWindowSize,
324    /// Challenge AVP
325    Challenge,
326    /// Cause Code AVP (Q.931)
327    Q931CauseCode,
328    /// Challenge Response AVP
329    ChallengeResponse,
330    /// Assigned Session ID AVP
331    AssignedSessionId,
332    /// Call Serial Number AVP
333    CallSerialNumber,
334    /// Minimum BPS AVP
335    MinimumBps,
336    /// Maximum BPS AVP
337    MaximumBps,
338    /// Bearer Type AVP
339    BearerType,
340    /// Framing Type AVP
341    FramingType,
342    /// Called Number AVP
343    CalledNumber,
344    /// Calling Number AVP
345    CallingNumber,
346    /// Sub-Address AVP
347    SubAddress,
348    /// Tx Connect Speed AVP
349    TxConnectSpeed,
350    /// Physical Channel ID AVP
351    PhysicalChannelId,
352    /// Initial Received LCP CONFREQ AVP
353    InitialReceivedLcpConfreq,
354    /// Last Sent LCP CONFREQ AVP
355    LastSentLcpConfreq,
356    /// Last Received LCP CONFREQ AVP
357    LastReceivedLcpConfreq,
358    /// Proxy Authen Type AVP
359    ProxyAuthenType,
360    /// Proxy Authen Name AVP
361    ProxyAuthenName,
362    /// Proxy Authen Challenge AVP
363    ProxyAuthenChallenge,
364    /// Proxy Authen ID AVP
365    ProxyAuthenId,
366    /// Proxy Authen Response AVP
367    ProxyAuthenResponse,
368    /// Call Errors AVP
369    CallErrors,
370    /// ACCM AVP
371    Accm,
372    /// Random Vector AVP
373    RandomVector,
374    /// Private Group ID AVP
375    PrivateGroupId,
376    /// Rx Connect Speed AVP
377    RxConnectSpeed,
378    /// Sequencing Required AVP
379    SequencingRequired,
380    /// Unknown AVP type
381    Unknown(u16),
382}
383
384impl From<u16> for L2tpAvpType {
385    fn from(value: u16) -> Self {
386        match value {
387            0 => L2tpAvpType::MessageType,
388            1 => L2tpAvpType::ResultCode,
389            2 => L2tpAvpType::ProtocolVersion,
390            3 => L2tpAvpType::FramingCapabilities,
391            4 => L2tpAvpType::BearerCapabilities,
392            5 => L2tpAvpType::TieBreaker,
393            6 => L2tpAvpType::FirmwareRevision,
394            7 => L2tpAvpType::HostName,
395            8 => L2tpAvpType::VendorName,
396            9 => L2tpAvpType::AssignedTunnelId,
397            10 => L2tpAvpType::ReceiveWindowSize,
398            11 => L2tpAvpType::Challenge,
399            12 => L2tpAvpType::Q931CauseCode,
400            13 => L2tpAvpType::ChallengeResponse,
401            14 => L2tpAvpType::AssignedSessionId,
402            15 => L2tpAvpType::CallSerialNumber,
403            16 => L2tpAvpType::MinimumBps,
404            17 => L2tpAvpType::MaximumBps,
405            18 => L2tpAvpType::BearerType,
406            19 => L2tpAvpType::FramingType,
407            21 => L2tpAvpType::CalledNumber,
408            22 => L2tpAvpType::CallingNumber,
409            23 => L2tpAvpType::SubAddress,
410            24 => L2tpAvpType::TxConnectSpeed,
411            25 => L2tpAvpType::PhysicalChannelId,
412            26 => L2tpAvpType::InitialReceivedLcpConfreq,
413            27 => L2tpAvpType::LastSentLcpConfreq,
414            28 => L2tpAvpType::LastReceivedLcpConfreq,
415            29 => L2tpAvpType::ProxyAuthenType,
416            30 => L2tpAvpType::ProxyAuthenName,
417            31 => L2tpAvpType::ProxyAuthenChallenge,
418            32 => L2tpAvpType::ProxyAuthenId,
419            33 => L2tpAvpType::ProxyAuthenResponse,
420            34 => L2tpAvpType::CallErrors,
421            35 => L2tpAvpType::Accm,
422            36 => L2tpAvpType::RandomVector,
423            37 => L2tpAvpType::PrivateGroupId,
424            38 => L2tpAvpType::RxConnectSpeed,
425            39 => L2tpAvpType::SequencingRequired,
426            v => L2tpAvpType::Unknown(v),
427        }
428    }
429}
430
431impl fmt::Display for L2tpAvpType {
432    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
433        match self {
434            L2tpAvpType::MessageType => write!(f, "Message Type"),
435            L2tpAvpType::ResultCode => write!(f, "Result Code"),
436            L2tpAvpType::ProtocolVersion => write!(f, "Protocol Version"),
437            L2tpAvpType::FramingCapabilities => write!(f, "Framing Capabilities"),
438            L2tpAvpType::BearerCapabilities => write!(f, "Bearer Capabilities"),
439            L2tpAvpType::TieBreaker => write!(f, "Tie Breaker"),
440            L2tpAvpType::FirmwareRevision => write!(f, "Firmware Revision"),
441            L2tpAvpType::HostName => write!(f, "Host Name"),
442            L2tpAvpType::VendorName => write!(f, "Vendor Name"),
443            L2tpAvpType::AssignedTunnelId => write!(f, "Assigned Tunnel ID"),
444            L2tpAvpType::ReceiveWindowSize => write!(f, "Receive Window Size"),
445            L2tpAvpType::Challenge => write!(f, "Challenge"),
446            L2tpAvpType::Q931CauseCode => write!(f, "Q.931 Cause Code"),
447            L2tpAvpType::ChallengeResponse => write!(f, "Challenge Response"),
448            L2tpAvpType::AssignedSessionId => write!(f, "Assigned Session ID"),
449            L2tpAvpType::CallSerialNumber => write!(f, "Call Serial Number"),
450            L2tpAvpType::MinimumBps => write!(f, "Minimum BPS"),
451            L2tpAvpType::MaximumBps => write!(f, "Maximum BPS"),
452            L2tpAvpType::BearerType => write!(f, "Bearer Type"),
453            L2tpAvpType::FramingType => write!(f, "Framing Type"),
454            L2tpAvpType::CalledNumber => write!(f, "Called Number"),
455            L2tpAvpType::CallingNumber => write!(f, "Calling Number"),
456            L2tpAvpType::SubAddress => write!(f, "Sub-Address"),
457            L2tpAvpType::TxConnectSpeed => write!(f, "Tx Connect Speed"),
458            L2tpAvpType::PhysicalChannelId => write!(f, "Physical Channel ID"),
459            L2tpAvpType::InitialReceivedLcpConfreq => write!(f, "Initial Received LCP CONFREQ"),
460            L2tpAvpType::LastSentLcpConfreq => write!(f, "Last Sent LCP CONFREQ"),
461            L2tpAvpType::LastReceivedLcpConfreq => write!(f, "Last Received LCP CONFREQ"),
462            L2tpAvpType::ProxyAuthenType => write!(f, "Proxy Authen Type"),
463            L2tpAvpType::ProxyAuthenName => write!(f, "Proxy Authen Name"),
464            L2tpAvpType::ProxyAuthenChallenge => write!(f, "Proxy Authen Challenge"),
465            L2tpAvpType::ProxyAuthenId => write!(f, "Proxy Authen ID"),
466            L2tpAvpType::ProxyAuthenResponse => write!(f, "Proxy Authen Response"),
467            L2tpAvpType::CallErrors => write!(f, "Call Errors"),
468            L2tpAvpType::Accm => write!(f, "ACCM"),
469            L2tpAvpType::RandomVector => write!(f, "Random Vector"),
470            L2tpAvpType::PrivateGroupId => write!(f, "Private Group ID"),
471            L2tpAvpType::RxConnectSpeed => write!(f, "Rx Connect Speed"),
472            L2tpAvpType::SequencingRequired => write!(f, "Sequencing Required"),
473            L2tpAvpType::Unknown(v) => write!(f, "Unknown({})", v),
474        }
475    }
476}
477
478/// L2TPv2 Header (fixed 6 bytes: flags + tunnel ID + session ID)
479///
480/// The minimum L2TPv2 header contains:
481/// - 2 bytes: Flags and Version
482/// - 2 bytes: Tunnel ID
483/// - 2 bytes: Session ID
484///
485/// Optional fields (Length, Ns, Nr, Offset) follow based on flags.
486#[repr(C, packed)]
487#[derive(
488    FromBytes, IntoBytes, Unaligned, Debug, Clone, Copy, zerocopy::KnownLayout, zerocopy::Immutable,
489)]
490pub struct L2tpv2Header {
491    flags_version: U16<BigEndian>,
492    tunnel_id: U16<BigEndian>,
493    session_id: U16<BigEndian>,
494}
495
496impl L2tpv2Header {
497    // L2TPv2 Flags (in the high byte of flags_version)
498    /// Type bit: 1 = Control message, 0 = Data message
499    pub const FLAG_TYPE: u16 = 0x8000;
500    /// Length bit: Length field present
501    pub const FLAG_LENGTH: u16 = 0x4000;
502    /// Sequence bit: Ns and Nr fields present
503    pub const FLAG_SEQUENCE: u16 = 0x0800;
504    /// Offset bit: Offset Size field present
505    pub const FLAG_OFFSET: u16 = 0x0200;
506    /// Priority bit: Priority delivery required
507    pub const FLAG_PRIORITY: u16 = 0x0100;
508
509    /// Version mask (bits 0-3)
510    pub const VERSION_MASK: u16 = 0x000F;
511
512    /// L2TPv2 version number
513    pub const VERSION_2: u16 = 0x0002;
514
515    /// Minimum header length (no optional fields)
516    pub const MIN_HEADER_LEN: usize = 6;
517
518    /// Length field size
519    pub const LENGTH_FIELD_SIZE: usize = 2;
520
521    /// Sequence fields size (Ns + Nr)
522    pub const SEQUENCE_FIELDS_SIZE: usize = 4;
523
524    /// Offset field size
525    pub const OFFSET_FIELD_SIZE: usize = 2;
526
527    #[allow(unused)]
528    const NAME: &'static str = "L2TPv2";
529
530    /// Get the raw flags and version field
531    #[inline]
532    pub fn flags_version(&self) -> u16 {
533        self.flags_version.get()
534    }
535
536    /// Get the protocol version
537    #[inline]
538    pub fn version(&self) -> u16 {
539        self.flags_version.get() & Self::VERSION_MASK
540    }
541
542    /// Check if this is a control message (T=1) or data message (T=0)
543    #[inline]
544    pub fn is_control(&self) -> bool {
545        (self.flags_version.get() & Self::FLAG_TYPE) != 0
546    }
547
548    /// Check if this is a data message
549    #[inline]
550    pub fn is_data(&self) -> bool {
551        !self.is_control()
552    }
553
554    /// Check if length field is present
555    #[inline]
556    pub fn has_length(&self) -> bool {
557        (self.flags_version.get() & Self::FLAG_LENGTH) != 0
558    }
559
560    /// Check if sequence fields (Ns, Nr) are present
561    #[inline]
562    pub fn has_sequence(&self) -> bool {
563        (self.flags_version.get() & Self::FLAG_SEQUENCE) != 0
564    }
565
566    /// Check if offset field is present
567    #[inline]
568    pub fn has_offset(&self) -> bool {
569        (self.flags_version.get() & Self::FLAG_OFFSET) != 0
570    }
571
572    /// Check if priority bit is set
573    #[inline]
574    pub fn has_priority(&self) -> bool {
575        (self.flags_version.get() & Self::FLAG_PRIORITY) != 0
576    }
577
578    /// Get the Tunnel ID
579    #[inline]
580    pub fn tunnel_id(&self) -> u16 {
581        self.tunnel_id.get()
582    }
583
584    /// Get the Session ID
585    #[inline]
586    pub fn session_id(&self) -> u16 {
587        self.session_id.get()
588    }
589
590    /// Check if this header has optional fields
591    #[inline]
592    pub fn has_optional_fields(&self) -> bool {
593        self.has_length() || self.has_sequence() || self.has_offset()
594    }
595
596    /// Calculate the total header length including optional fields
597    #[inline]
598    pub fn header_length(&self) -> usize {
599        let mut len = Self::MIN_HEADER_LEN;
600        if self.has_length() {
601            len += Self::LENGTH_FIELD_SIZE;
602        }
603        if self.has_sequence() {
604            len += Self::SEQUENCE_FIELDS_SIZE;
605        }
606        if self.has_offset() {
607            len += Self::OFFSET_FIELD_SIZE;
608        }
609        len
610    }
611
612    /// Validate the header
613    fn is_valid(&self) -> bool {
614        // Version must be 2
615        if self.version() != Self::VERSION_2 {
616            return false;
617        }
618        // Control messages must have L and S bits set
619        if self.is_control() && (!self.has_length() || !self.has_sequence()) {
620            return false;
621        }
622        true
623    }
624
625    /// Get a string representation of the flags
626    pub fn flags_string(&self) -> String {
627        let mut flags = Vec::new();
628        if self.is_control() {
629            flags.push("T");
630        }
631        if self.has_length() {
632            flags.push("L");
633        }
634        if self.has_sequence() {
635            flags.push("S");
636        }
637        if self.has_offset() {
638            flags.push("O");
639        }
640        if self.has_priority() {
641            flags.push("P");
642        }
643        if flags.is_empty() {
644            "none".to_string()
645        } else {
646            flags.join("|")
647        }
648    }
649}
650
651/// L2TPv2 Header with optional fields
652#[derive(Debug, Clone)]
653pub struct L2tpv2HeaderOpt<'a> {
654    /// The fixed header
655    pub header: &'a L2tpv2Header,
656    /// Raw bytes of optional fields
657    pub raw_options: &'a [u8],
658}
659
660impl<'a> L2tpv2HeaderOpt<'a> {
661    /// Get the length field value (if L bit is set)
662    ///
663    /// The length field is inserted between flags_version and tunnel_id
664    /// in the wire format, but since we parse tunnel_id/session_id as
665    /// part of the fixed header, we need to look at raw_options.
666    pub fn length(&self) -> Option<u16> {
667        if self.header.has_length() && self.raw_options.len() >= 2 {
668            Some(u16::from_be_bytes([
669                self.raw_options[0],
670                self.raw_options[1],
671            ]))
672        } else {
673            None
674        }
675    }
676
677    /// Get the sequence number Ns (if S bit is set)
678    pub fn ns(&self) -> Option<u16> {
679        if !self.header.has_sequence() {
680            return None;
681        }
682        let offset = if self.header.has_length() { 2 } else { 0 };
683        if self.raw_options.len() >= offset + 2 {
684            Some(u16::from_be_bytes([
685                self.raw_options[offset],
686                self.raw_options[offset + 1],
687            ]))
688        } else {
689            None
690        }
691    }
692
693    /// Get the expected sequence number Nr (if S bit is set)
694    pub fn nr(&self) -> Option<u16> {
695        if !self.header.has_sequence() {
696            return None;
697        }
698        let offset = if self.header.has_length() { 4 } else { 2 };
699        if self.raw_options.len() >= offset + 2 {
700            Some(u16::from_be_bytes([
701                self.raw_options[offset],
702                self.raw_options[offset + 1],
703            ]))
704        } else {
705            None
706        }
707    }
708
709    /// Get the offset size (if O bit is set)
710    pub fn offset_size(&self) -> Option<u16> {
711        if !self.header.has_offset() {
712            return None;
713        }
714        let mut offset = 0;
715        if self.header.has_length() {
716            offset += 2;
717        }
718        if self.header.has_sequence() {
719            offset += 4;
720        }
721        if self.raw_options.len() >= offset + 2 {
722            Some(u16::from_be_bytes([
723                self.raw_options[offset],
724                self.raw_options[offset + 1],
725            ]))
726        } else {
727            None
728        }
729    }
730
731    /// Get an iterator over AVPs (for control messages)
732    pub fn avps(&self) -> L2tpAvpIter<'a> {
733        if !self.header.is_control() {
734            return L2tpAvpIter { data: &[] };
735        }
736        // AVPs start after the header
737        L2tpAvpIter { data: &[] } // AVPs are in the payload, not raw_options
738    }
739}
740
741impl std::ops::Deref for L2tpv2HeaderOpt<'_> {
742    type Target = L2tpv2Header;
743
744    #[inline]
745    fn deref(&self) -> &Self::Target {
746        self.header
747    }
748}
749
750/// L2TP AVP Header (6 bytes minimum)
751#[repr(C, packed)]
752#[derive(
753    FromBytes, IntoBytes, Unaligned, Debug, Clone, Copy, zerocopy::KnownLayout, zerocopy::Immutable,
754)]
755pub struct L2tpAvpHeader {
756    flags_length: U16<BigEndian>,
757    vendor_id: U16<BigEndian>,
758    attribute_type: U16<BigEndian>,
759}
760
761impl L2tpAvpHeader {
762    /// Mandatory bit
763    pub const FLAG_MANDATORY: u16 = 0x8000;
764    /// Hidden bit (value is hidden)
765    pub const FLAG_HIDDEN: u16 = 0x4000;
766    /// Length mask (bits 0-9)
767    pub const LENGTH_MASK: u16 = 0x03FF;
768
769    /// Minimum AVP header size
770    pub const HEADER_SIZE: usize = 6;
771
772    /// Check if this AVP is mandatory
773    #[inline]
774    pub fn is_mandatory(&self) -> bool {
775        (self.flags_length.get() & Self::FLAG_MANDATORY) != 0
776    }
777
778    /// Check if this AVP value is hidden
779    #[inline]
780    pub fn is_hidden(&self) -> bool {
781        (self.flags_length.get() & Self::FLAG_HIDDEN) != 0
782    }
783
784    /// Get the total length of this AVP (including header)
785    #[inline]
786    pub fn length(&self) -> u16 {
787        self.flags_length.get() & Self::LENGTH_MASK
788    }
789
790    /// Get the vendor ID (0 for IETF-defined AVPs)
791    #[inline]
792    pub fn vendor_id(&self) -> u16 {
793        self.vendor_id.get()
794    }
795
796    /// Get the attribute type
797    #[inline]
798    pub fn attribute_type(&self) -> u16 {
799        self.attribute_type.get()
800    }
801
802    /// Get the attribute type as enum
803    #[inline]
804    pub fn attribute_type_enum(&self) -> L2tpAvpType {
805        L2tpAvpType::from(self.attribute_type.get())
806    }
807
808    /// Get the value length (total length - header size)
809    #[inline]
810    pub fn value_length(&self) -> usize {
811        let total = self.length() as usize;
812        total.saturating_sub(Self::HEADER_SIZE)
813    }
814}
815
816/// A parsed L2TP AVP
817#[derive(Debug, Clone)]
818pub struct L2tpAvp<'a> {
819    /// AVP header
820    pub header: &'a L2tpAvpHeader,
821    /// AVP value
822    pub value: &'a [u8],
823}
824
825impl<'a> L2tpAvp<'a> {
826    /// Check if this is a Message Type AVP
827    #[inline]
828    pub fn is_message_type(&self) -> bool {
829        self.header.vendor_id() == 0 && self.header.attribute_type() == 0
830    }
831
832    /// Get the message type value (if this is a Message Type AVP)
833    pub fn message_type(&self) -> Option<L2tpv2MessageType> {
834        if self.is_message_type() && self.value.len() >= 2 {
835            let msg_type = u16::from_be_bytes([self.value[0], self.value[1]]);
836            Some(L2tpv2MessageType::from(msg_type))
837        } else {
838            None
839        }
840    }
841}
842
843/// Iterator over L2TP AVPs
844#[derive(Debug, Clone)]
845pub struct L2tpAvpIter<'a> {
846    data: &'a [u8],
847}
848
849impl<'a> Iterator for L2tpAvpIter<'a> {
850    type Item = L2tpAvp<'a>;
851
852    fn next(&mut self) -> Option<Self::Item> {
853        if self.data.len() < L2tpAvpHeader::HEADER_SIZE {
854            return None;
855        }
856
857        // Parse the AVP header
858        let header = zerocopy::Ref::<_, L2tpAvpHeader>::from_prefix(self.data)
859            .ok()
860            .map(|(header_ref, _)| zerocopy::Ref::into_ref(header_ref))?;
861
862        let total_len = header.length() as usize;
863        if total_len < L2tpAvpHeader::HEADER_SIZE || total_len > self.data.len() {
864            self.data = &[];
865            return None;
866        }
867
868        let value_start = L2tpAvpHeader::HEADER_SIZE;
869        let value = &self.data[value_start..total_len];
870
871        // Advance to next AVP
872        self.data = &self.data[total_len..];
873
874        Some(L2tpAvp { header, value })
875    }
876}
877
878impl PacketHeader for L2tpv2Header {
879    const NAME: &'static str = "L2TPv2";
880
881    type InnerType = ();
882
883    #[inline]
884    fn inner_type(&self) -> Self::InnerType {}
885
886    #[inline]
887    fn total_len(&self, _buf: &[u8]) -> usize {
888        self.header_length()
889    }
890
891    #[inline]
892    fn is_valid(&self) -> bool {
893        L2tpv2Header::is_valid(self)
894    }
895}
896
897impl HeaderParser for L2tpv2Header {
898    type Output<'a> = L2tpv2HeaderOpt<'a>;
899
900    fn into_view<'a>(header: &'a Self, options: &'a [u8]) -> Self::Output<'a> {
901        L2tpv2HeaderOpt {
902            header,
903            raw_options: options,
904        }
905    }
906}
907
908impl fmt::Display for L2tpv2Header {
909    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
910        write!(
911            f,
912            "L2TPv{} {} tunnel={} session={} flags=[{}]",
913            self.version(),
914            if self.is_control() { "CTRL" } else { "DATA" },
915            self.tunnel_id(),
916            self.session_id(),
917            self.flags_string()
918        )
919    }
920}
921
922impl fmt::Display for L2tpv2HeaderOpt<'_> {
923    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
924        write!(
925            f,
926            "L2TPv{} {} tunnel={} session={} flags=[{}]",
927            self.version(),
928            if self.is_control() { "CTRL" } else { "DATA" },
929            self.tunnel_id(),
930            self.session_id(),
931            self.flags_string()
932        )?;
933        if let Some(len) = self.length() {
934            write!(f, " len={}", len)?;
935        }
936        if let Some(ns) = self.ns() {
937            write!(f, " Ns={}", ns)?;
938        }
939        if let Some(nr) = self.nr() {
940            write!(f, " Nr={}", nr)?;
941        }
942        if let Some(offset) = self.offset_size() {
943            write!(f, " offset={}", offset)?;
944        }
945        Ok(())
946    }
947}
948
949// ============================================================================
950// L2TPv3 Support
951// ============================================================================
952
953/// L2TPv3 Session Header for data messages (over IP or UDP)
954///
955/// When L2TPv3 data is sent directly over IP (protocol 115), or over UDP
956/// with a zero Session ID in the first 4 bytes indicating a data message,
957/// this simple header is used.
958///
959/// ```text
960///  0                   1                   2                   3
961///  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
962/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
963/// |                      Session ID (32 bits)                     |
964/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
965/// |               Cookie (optional, variable length)              |
966/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
967/// ```
968#[repr(C, packed)]
969#[derive(
970    FromBytes, IntoBytes, Unaligned, Debug, Clone, Copy, zerocopy::KnownLayout, zerocopy::Immutable,
971)]
972pub struct L2tpv3SessionHeader {
973    session_id: U32<BigEndian>,
974}
975
976impl L2tpv3SessionHeader {
977    /// Minimum header size (just session ID)
978    pub const MIN_HEADER_LEN: usize = 4;
979
980    #[allow(unused)]
981    const NAME: &'static str = "L2TPv3-Session";
982
983    /// Get the session ID
984    #[inline]
985    pub fn session_id(&self) -> u32 {
986        self.session_id.get()
987    }
988
989    /// Check if this is a valid L2TPv3 data session header
990    /// Session ID of 0 indicates a control message, not data
991    #[inline]
992    fn is_valid(&self) -> bool {
993        self.session_id.get() != 0
994    }
995}
996
997/// L2TPv3 Session Header with optional cookie
998#[derive(Debug, Clone)]
999pub struct L2tpv3SessionHeaderCookie<'a> {
1000    /// The fixed header
1001    pub header: &'a L2tpv3SessionHeader,
1002    /// Cookie bytes (0, 4, or 8 bytes depending on configuration)
1003    pub cookie: &'a [u8],
1004}
1005
1006impl<'a> L2tpv3SessionHeaderCookie<'a> {
1007    /// Get the cookie as a 32-bit value (if 4-byte cookie)
1008    pub fn cookie_32(&self) -> Option<u32> {
1009        if self.cookie.len() >= 4 {
1010            Some(u32::from_be_bytes([
1011                self.cookie[0],
1012                self.cookie[1],
1013                self.cookie[2],
1014                self.cookie[3],
1015            ]))
1016        } else {
1017            None
1018        }
1019    }
1020
1021    /// Get the cookie as a 64-bit value (if 8-byte cookie)
1022    pub fn cookie_64(&self) -> Option<u64> {
1023        if self.cookie.len() >= 8 {
1024            Some(u64::from_be_bytes([
1025                self.cookie[0],
1026                self.cookie[1],
1027                self.cookie[2],
1028                self.cookie[3],
1029                self.cookie[4],
1030                self.cookie[5],
1031                self.cookie[6],
1032                self.cookie[7],
1033            ]))
1034        } else {
1035            None
1036        }
1037    }
1038}
1039
1040impl std::ops::Deref for L2tpv3SessionHeaderCookie<'_> {
1041    type Target = L2tpv3SessionHeader;
1042
1043    #[inline]
1044    fn deref(&self) -> &Self::Target {
1045        self.header
1046    }
1047}
1048
1049impl PacketHeader for L2tpv3SessionHeader {
1050    const NAME: &'static str = "L2TPv3-Session";
1051
1052    type InnerType = ();
1053
1054    #[inline]
1055    fn inner_type(&self) -> Self::InnerType {}
1056
1057    #[inline]
1058    fn total_len(&self, _buf: &[u8]) -> usize {
1059        // Cookie length is negotiated out-of-band, so we return minimum
1060        // The caller should use parse_with_cookie_len for proper parsing
1061        Self::MIN_HEADER_LEN
1062    }
1063
1064    #[inline]
1065    fn is_valid(&self) -> bool {
1066        L2tpv3SessionHeader::is_valid(self)
1067    }
1068}
1069
1070impl HeaderParser for L2tpv3SessionHeader {
1071    type Output<'a> = L2tpv3SessionHeaderCookie<'a>;
1072
1073    fn into_view<'a>(header: &'a Self, options: &'a [u8]) -> Self::Output<'a> {
1074        L2tpv3SessionHeaderCookie {
1075            header,
1076            cookie: options,
1077        }
1078    }
1079}
1080
1081impl L2tpv3SessionHeader {
1082    /// Parse L2TPv3 session header with a known cookie length
1083    ///
1084    /// Cookie length (0, 4, or 8 bytes) is negotiated during session setup.
1085    pub fn parse_with_cookie_len(
1086        buf: &[u8],
1087        cookie_len: usize,
1088    ) -> Result<(L2tpv3SessionHeaderCookie<'_>, &[u8]), PacketHeaderError> {
1089        if buf.len() < Self::MIN_HEADER_LEN + cookie_len {
1090            return Err(PacketHeaderError::TooShort("L2TPv3-Session"));
1091        }
1092
1093        let (header_ref, rest) = zerocopy::Ref::<_, Self>::from_prefix(buf)
1094            .map_err(|_| PacketHeaderError::TooShort("L2TPv3-Session"))?;
1095
1096        let header = zerocopy::Ref::into_ref(header_ref);
1097
1098        if !header.is_valid() {
1099            return Err(PacketHeaderError::Invalid("L2TPv3-Session"));
1100        }
1101
1102        let (cookie, payload) = rest.split_at(cookie_len);
1103
1104        Ok((L2tpv3SessionHeaderCookie { header, cookie }, payload))
1105    }
1106}
1107
1108impl fmt::Display for L2tpv3SessionHeader {
1109    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1110        write!(f, "L2TPv3 Session ID={}", self.session_id())
1111    }
1112}
1113
1114impl fmt::Display for L2tpv3SessionHeaderCookie<'_> {
1115    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1116        write!(f, "L2TPv3 Session ID={}", self.session_id())?;
1117        if let Some(cookie) = self.cookie_64() {
1118            write!(f, " Cookie=0x{:016x}", cookie)?;
1119        } else if let Some(cookie) = self.cookie_32() {
1120            write!(f, " Cookie=0x{:08x}", cookie)?;
1121        }
1122        Ok(())
1123    }
1124}
1125
1126/// L2TPv3 Control Message Header (for UDP encapsulation)
1127///
1128/// L2TPv3 control messages over UDP use a format similar to L2TPv2
1129/// but with version 3 and some differences.
1130///
1131/// ```text
1132///  0                   1                   2                   3
1133///  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1134/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1135/// |T|L|x|x|S|x|x|x|x|x|x|x|  Ver  |          Length               |
1136/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1137/// |                 Control Connection ID                         |
1138/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1139/// |               Ns              |               Nr              |
1140/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1141/// ```
1142#[repr(C, packed)]
1143#[derive(
1144    FromBytes, IntoBytes, Unaligned, Debug, Clone, Copy, zerocopy::KnownLayout, zerocopy::Immutable,
1145)]
1146pub struct L2tpv3ControlHeader {
1147    flags_version: U16<BigEndian>,
1148    length: U16<BigEndian>,
1149    control_connection_id: U32<BigEndian>,
1150    ns: U16<BigEndian>,
1151    nr: U16<BigEndian>,
1152}
1153
1154impl L2tpv3ControlHeader {
1155    /// Type bit: must be 1 for control messages
1156    pub const FLAG_TYPE: u16 = 0x8000;
1157    /// Length bit: must be 1 for control messages
1158    pub const FLAG_LENGTH: u16 = 0x4000;
1159    /// Sequence bit: must be 1 for control messages
1160    pub const FLAG_SEQUENCE: u16 = 0x0800;
1161
1162    /// Version mask (bits 0-3)
1163    pub const VERSION_MASK: u16 = 0x000F;
1164
1165    /// L2TPv3 version number
1166    pub const VERSION_3: u16 = 0x0003;
1167
1168    /// Fixed header size
1169    pub const HEADER_LEN: usize = 12;
1170
1171    #[allow(unused)]
1172    const NAME: &'static str = "L2TPv3-Control";
1173
1174    /// Get the raw flags and version field
1175    #[inline]
1176    pub fn flags_version(&self) -> u16 {
1177        self.flags_version.get()
1178    }
1179
1180    /// Get the protocol version
1181    #[inline]
1182    pub fn version(&self) -> u16 {
1183        self.flags_version.get() & Self::VERSION_MASK
1184    }
1185
1186    /// Check if this is a control message (T=1)
1187    #[inline]
1188    pub fn is_control(&self) -> bool {
1189        (self.flags_version.get() & Self::FLAG_TYPE) != 0
1190    }
1191
1192    /// Check if length field is present
1193    #[inline]
1194    pub fn has_length(&self) -> bool {
1195        (self.flags_version.get() & Self::FLAG_LENGTH) != 0
1196    }
1197
1198    /// Check if sequence fields are present
1199    #[inline]
1200    pub fn has_sequence(&self) -> bool {
1201        (self.flags_version.get() & Self::FLAG_SEQUENCE) != 0
1202    }
1203
1204    /// Get the length field
1205    #[inline]
1206    pub fn length(&self) -> u16 {
1207        self.length.get()
1208    }
1209
1210    /// Get the Control Connection ID
1211    #[inline]
1212    pub fn control_connection_id(&self) -> u32 {
1213        self.control_connection_id.get()
1214    }
1215
1216    /// Get the sequence number Ns
1217    #[inline]
1218    pub fn ns(&self) -> u16 {
1219        self.ns.get()
1220    }
1221
1222    /// Get the expected sequence number Nr
1223    #[inline]
1224    pub fn nr(&self) -> u16 {
1225        self.nr.get()
1226    }
1227
1228    /// Validate the header
1229    fn is_valid(&self) -> bool {
1230        // Version must be 3
1231        if self.version() != Self::VERSION_3 {
1232            return false;
1233        }
1234        // Control messages must have T, L, and S bits set
1235        if !self.is_control() || !self.has_length() || !self.has_sequence() {
1236            return false;
1237        }
1238        true
1239    }
1240
1241    /// Get a string representation of the flags
1242    pub fn flags_string(&self) -> String {
1243        let mut flags = Vec::new();
1244        if self.is_control() {
1245            flags.push("T");
1246        }
1247        if self.has_length() {
1248            flags.push("L");
1249        }
1250        if self.has_sequence() {
1251            flags.push("S");
1252        }
1253        if flags.is_empty() {
1254            "none".to_string()
1255        } else {
1256            flags.join("|")
1257        }
1258    }
1259}
1260
1261impl PacketHeader for L2tpv3ControlHeader {
1262    const NAME: &'static str = "L2TPv3-Control";
1263
1264    type InnerType = ();
1265
1266    #[inline]
1267    fn inner_type(&self) -> Self::InnerType {}
1268
1269    #[inline]
1270    fn total_len(&self, _buf: &[u8]) -> usize {
1271        Self::HEADER_LEN
1272    }
1273
1274    #[inline]
1275    fn is_valid(&self) -> bool {
1276        L2tpv3ControlHeader::is_valid(self)
1277    }
1278}
1279
1280impl HeaderParser for L2tpv3ControlHeader {
1281    type Output<'a> = &'a L2tpv3ControlHeader;
1282
1283    fn into_view<'a>(header: &'a Self, _options: &'a [u8]) -> Self::Output<'a> {
1284        header
1285    }
1286}
1287
1288impl fmt::Display for L2tpv3ControlHeader {
1289    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1290        write!(
1291            f,
1292            "L2TPv3 CTRL CCID={} Ns={} Nr={} len={} flags=[{}]",
1293            self.control_connection_id(),
1294            self.ns(),
1295            self.nr(),
1296            self.length(),
1297            self.flags_string()
1298        )
1299    }
1300}
1301
1302/// Helper to distinguish L2TPv2 vs L2TPv3 by looking at the version field
1303pub fn detect_l2tp_version(buf: &[u8]) -> Option<u16> {
1304    if buf.len() < 2 {
1305        return None;
1306    }
1307    let flags_version = u16::from_be_bytes([buf[0], buf[1]]);
1308    Some(flags_version & 0x000F)
1309}
1310
1311/// Check if this looks like an L2TPv3 data session (Session ID != 0 in first 4 bytes)
1312/// This is used when parsing L2TPv3 over IP (protocol 115)
1313pub fn is_l2tpv3_data_session(buf: &[u8]) -> bool {
1314    if buf.len() < 4 {
1315        return false;
1316    }
1317    let session_id = u32::from_be_bytes([buf[0], buf[1], buf[2], buf[3]]);
1318    session_id != 0
1319}
1320
1321#[cfg(test)]
1322mod tests {
1323    use super::*;
1324    use crate::packet::HeaderParser;
1325
1326    #[test]
1327    fn test_l2tpv2_header_size() {
1328        assert_eq!(std::mem::size_of::<L2tpv2Header>(), 6);
1329        assert_eq!(L2tpv2Header::MIN_HEADER_LEN, 6);
1330    }
1331
1332    #[test]
1333    fn test_l2tpv2_data_basic() {
1334        // L2TPv2 data packet (minimal)
1335        let packet = vec![
1336            0x00, 0x02, // flags: T=0, L=0, S=0, O=0, P=0, Ver=2
1337            0x00, 0x01, // Tunnel ID: 1
1338            0x00, 0x02, // Session ID: 2
1339            // PPP payload
1340            0xFF, 0x03, 0x00, 0x21,
1341        ];
1342
1343        let (header, payload) = L2tpv2Header::from_bytes(&packet).unwrap();
1344        assert_eq!(header.version(), 2);
1345        assert!(!header.is_control());
1346        assert!(header.is_data());
1347        assert!(!header.has_length());
1348        assert!(!header.has_sequence());
1349        assert!(!header.has_offset());
1350        assert!(!header.has_priority());
1351        assert_eq!(header.tunnel_id(), 1);
1352        assert_eq!(header.session_id(), 2);
1353        assert_eq!(payload.len(), 4);
1354    }
1355
1356    #[test]
1357    fn test_l2tpv2_control_with_sequence() {
1358        // L2TPv2 control message with L and S bits
1359        let packet = vec![
1360            0xC8, 0x02, // flags: T=1, L=1, S=1, Ver=2
1361            0x00, 0x01, // Tunnel ID: 1
1362            0x00, 0x00, // Session ID: 0 (control)
1363            // Optional fields
1364            0x00, 0x10, // Length: 16
1365            0x00, 0x01, // Ns: 1
1366            0x00, 0x02, // Nr: 2
1367            // AVP payload
1368            0x00, 0x08, 0x00, 0x00,
1369        ];
1370
1371        let (header, _payload) = L2tpv2Header::from_bytes(&packet).unwrap();
1372        assert_eq!(header.version(), 2);
1373        assert!(header.is_control());
1374        assert!(header.has_length());
1375        assert!(header.has_sequence());
1376        assert_eq!(header.tunnel_id(), 1);
1377        assert_eq!(header.session_id(), 0);
1378        assert_eq!(header.length(), Some(16));
1379        assert_eq!(header.ns(), Some(1));
1380        assert_eq!(header.nr(), Some(2));
1381    }
1382
1383    #[test]
1384    fn test_l2tpv2_with_offset() {
1385        // L2TPv2 data with offset field
1386        let packet = vec![
1387            0x02, 0x02, // flags: O=1, Ver=2
1388            0x00, 0x01, // Tunnel ID: 1
1389            0x00, 0x02, // Session ID: 2
1390            // Optional fields
1391            0x00, 0x04, // Offset Size: 4
1392            // Payload
1393            0xFF, 0x03,
1394        ];
1395
1396        let (header, _payload) = L2tpv2Header::from_bytes(&packet).unwrap();
1397        assert!(header.has_offset());
1398        assert_eq!(header.offset_size(), Some(4));
1399    }
1400
1401    #[test]
1402    fn test_l2tpv2_with_priority() {
1403        // L2TPv2 data with priority bit
1404        let packet = vec![
1405            0x01, 0x02, // flags: P=1, Ver=2
1406            0x00, 0x01, // Tunnel ID: 1
1407            0x00, 0x02, // Session ID: 2
1408            // Payload
1409            0xFF, 0x03,
1410        ];
1411
1412        let (header, _payload) = L2tpv2Header::from_bytes(&packet).unwrap();
1413        assert!(header.has_priority());
1414        assert!(header.is_data());
1415    }
1416
1417    #[test]
1418    fn test_l2tpv2_invalid_version() {
1419        // Invalid version (not 2)
1420        let packet = vec![
1421            0x00, 0x03, // flags: Ver=3 (invalid for L2TPv2Header)
1422            0x00, 0x01, // Tunnel ID: 1
1423            0x00, 0x02, // Session ID: 2
1424        ];
1425
1426        let result = L2tpv2Header::from_bytes(&packet);
1427        assert!(result.is_err());
1428    }
1429
1430    #[test]
1431    fn test_l2tpv2_control_missing_length() {
1432        // Control message without L bit (invalid)
1433        let packet = vec![
1434            0x88, 0x02, // flags: T=1, S=1, Ver=2 (missing L)
1435            0x00, 0x01, // Tunnel ID: 1
1436            0x00, 0x00, // Session ID: 0
1437        ];
1438
1439        let result = L2tpv2Header::from_bytes(&packet);
1440        assert!(result.is_err());
1441    }
1442
1443    #[test]
1444    fn test_l2tpv2_flags_string() {
1445        // Control with all common flags
1446        let packet = vec![
1447            0xC9, 0x02, // flags: T=1, L=1, S=0, O=0, P=1, Ver=2
1448            0x00, 0x01, // Tunnel ID
1449            0x00, 0x00, // Session ID
1450            0x00, 0x10, // Length
1451            0x00, 0x01, // Ns
1452            0x00, 0x00, // Nr
1453        ];
1454
1455        let (header, _) = L2tpv2Header::from_bytes(&packet).unwrap();
1456        let flags = header.flags_string();
1457        assert!(flags.contains("T"));
1458        assert!(flags.contains("L"));
1459        assert!(flags.contains("P"));
1460    }
1461
1462    #[test]
1463    fn test_l2tpv2_display() {
1464        let packet = vec![
1465            0x00, 0x02, // flags: Ver=2
1466            0x00, 0x0A, // Tunnel ID: 10
1467            0x00, 0x14, // Session ID: 20
1468            0xFF, 0x03,
1469        ];
1470
1471        let (header, _) = L2tpv2Header::from_bytes(&packet).unwrap();
1472        let display = format!("{}", header);
1473        assert!(display.contains("L2TPv2"));
1474        assert!(display.contains("DATA"));
1475        assert!(display.contains("tunnel=10"));
1476        assert!(display.contains("session=20"));
1477    }
1478
1479    #[test]
1480    fn test_l2tpv2_too_short() {
1481        let packet = vec![0x00, 0x02, 0x00];
1482        let result = L2tpv2Header::from_bytes(&packet);
1483        assert!(result.is_err());
1484    }
1485
1486    #[test]
1487    fn test_l2tpv2_message_types() {
1488        assert_eq!(L2tpv2MessageType::from(1), L2tpv2MessageType::Sccrq);
1489        assert_eq!(L2tpv2MessageType::from(2), L2tpv2MessageType::Sccrp);
1490        assert_eq!(L2tpv2MessageType::from(3), L2tpv2MessageType::Scccn);
1491        assert_eq!(L2tpv2MessageType::from(4), L2tpv2MessageType::StopCcn);
1492        assert_eq!(L2tpv2MessageType::from(6), L2tpv2MessageType::Hello);
1493        assert_eq!(L2tpv2MessageType::from(14), L2tpv2MessageType::Cdn);
1494        assert_eq!(L2tpv2MessageType::from(0), L2tpv2MessageType::Zlb);
1495        assert_eq!(
1496            L2tpv2MessageType::from(255),
1497            L2tpv2MessageType::Unknown(255)
1498        );
1499    }
1500
1501    #[test]
1502    fn test_l2tpv2_message_type_display() {
1503        assert_eq!(format!("{}", L2tpv2MessageType::Sccrq), "SCCRQ");
1504        assert_eq!(format!("{}", L2tpv2MessageType::Hello), "Hello");
1505        assert_eq!(format!("{}", L2tpv2MessageType::Unknown(99)), "Unknown(99)");
1506    }
1507
1508    #[test]
1509    fn test_l2tp_avp_types() {
1510        assert_eq!(L2tpAvpType::from(0), L2tpAvpType::MessageType);
1511        assert_eq!(L2tpAvpType::from(7), L2tpAvpType::HostName);
1512        assert_eq!(L2tpAvpType::from(9), L2tpAvpType::AssignedTunnelId);
1513        assert_eq!(L2tpAvpType::from(100), L2tpAvpType::Unknown(100));
1514    }
1515
1516    #[test]
1517    fn test_l2tp_port() {
1518        assert_eq!(L2TP_PORT, 1701);
1519        assert!(is_l2tp_port(1701));
1520        assert!(!is_l2tp_port(1702));
1521    }
1522
1523    #[test]
1524    fn test_l2tpv3_ip_proto() {
1525        assert_eq!(L2TPV3_IP_PROTO, 115);
1526        assert!(is_l2tpv3_proto(115));
1527        assert!(!is_l2tpv3_proto(114));
1528    }
1529
1530    // L2TPv3 Tests
1531
1532    #[test]
1533    fn test_l2tpv3_session_header_size() {
1534        assert_eq!(std::mem::size_of::<L2tpv3SessionHeader>(), 4);
1535    }
1536
1537    #[test]
1538    fn test_l2tpv3_session_basic() {
1539        // L2TPv3 data session (over IP)
1540        let packet = vec![
1541            0x00, 0x00, 0x12, 0x34, // Session ID: 0x1234
1542            // L2 payload follows
1543            0xFF, 0xFF, 0xFF, 0xFF,
1544        ];
1545
1546        let (header, payload) = L2tpv3SessionHeader::from_bytes(&packet).unwrap();
1547        assert_eq!(header.session_id(), 0x1234);
1548        assert_eq!(payload.len(), 4);
1549    }
1550
1551    #[test]
1552    fn test_l2tpv3_session_with_cookie_32() {
1553        let packet = vec![
1554            0x00, 0x00, 0x12, 0x34, // Session ID: 0x1234
1555            0xDE, 0xAD, 0xBE, 0xEF, // 32-bit cookie
1556            // Payload
1557            0xFF, 0xFF,
1558        ];
1559
1560        let (header, payload) = L2tpv3SessionHeader::parse_with_cookie_len(&packet, 4).unwrap();
1561        assert_eq!(header.session_id(), 0x1234);
1562        assert_eq!(header.cookie_32(), Some(0xDEADBEEF));
1563        assert_eq!(payload.len(), 2);
1564    }
1565
1566    #[test]
1567    fn test_l2tpv3_session_with_cookie_64() {
1568        let packet = vec![
1569            0x00, 0x00, 0x12, 0x34, // Session ID: 0x1234
1570            0xDE, 0xAD, 0xBE, 0xEF, // 64-bit cookie (high)
1571            0xCA, 0xFE, 0xBA, 0xBE, // 64-bit cookie (low)
1572            // Payload
1573            0xFF, 0xFF,
1574        ];
1575
1576        let (header, payload) = L2tpv3SessionHeader::parse_with_cookie_len(&packet, 8).unwrap();
1577        assert_eq!(header.session_id(), 0x1234);
1578        assert_eq!(header.cookie_64(), Some(0xDEADBEEFCAFEBABE));
1579        assert_eq!(payload.len(), 2);
1580    }
1581
1582    #[test]
1583    fn test_l2tpv3_session_zero_id_invalid() {
1584        // Session ID 0 means control message, not data
1585        let packet = vec![
1586            0x00, 0x00, 0x00, 0x00, // Session ID: 0 (invalid for data)
1587            0xFF, 0xFF,
1588        ];
1589
1590        let result = L2tpv3SessionHeader::from_bytes(&packet);
1591        assert!(result.is_err());
1592    }
1593
1594    #[test]
1595    fn test_l2tpv3_session_display() {
1596        let packet = vec![
1597            0x00, 0x00, 0xAB, 0xCD, // Session ID
1598            0x12, 0x34, 0x56, 0x78, // Cookie
1599        ];
1600
1601        let (header, _) = L2tpv3SessionHeader::parse_with_cookie_len(&packet, 4).unwrap();
1602        let display = format!("{}", header);
1603        assert!(display.contains("L2TPv3"));
1604        assert!(display.contains("Session ID"));
1605        assert!(display.contains("Cookie"));
1606    }
1607
1608    #[test]
1609    fn test_l2tpv3_control_header_size() {
1610        assert_eq!(std::mem::size_of::<L2tpv3ControlHeader>(), 12);
1611    }
1612
1613    #[test]
1614    fn test_l2tpv3_control_basic() {
1615        // L2TPv3 control message
1616        let packet = vec![
1617            0xC8, 0x03, // flags: T=1, L=1, S=1, Ver=3
1618            0x00, 0x14, // Length: 20
1619            0x00, 0x00, 0x00, 0x01, // Control Connection ID: 1
1620            0x00, 0x05, // Ns: 5
1621            0x00, 0x04, // Nr: 4
1622            // AVPs follow
1623            0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
1624        ];
1625
1626        let (header, payload) = L2tpv3ControlHeader::from_bytes(&packet).unwrap();
1627        assert_eq!(header.version(), 3);
1628        assert!(header.is_control());
1629        assert!(header.has_length());
1630        assert!(header.has_sequence());
1631        assert_eq!(header.length(), 20);
1632        assert_eq!(header.control_connection_id(), 1);
1633        assert_eq!(header.ns(), 5);
1634        assert_eq!(header.nr(), 4);
1635        assert_eq!(payload.len(), 8);
1636    }
1637
1638    #[test]
1639    fn test_l2tpv3_control_invalid_version() {
1640        // Invalid version
1641        let packet = vec![
1642            0xC8, 0x02, // flags: T=1, L=1, S=1, Ver=2 (wrong)
1643            0x00, 0x14, // Length
1644            0x00, 0x00, 0x00, 0x01, // CCID
1645            0x00, 0x05, // Ns
1646            0x00, 0x04, // Nr
1647        ];
1648
1649        let result = L2tpv3ControlHeader::from_bytes(&packet);
1650        assert!(result.is_err());
1651    }
1652
1653    #[test]
1654    fn test_l2tpv3_control_display() {
1655        let packet = vec![
1656            0xC8, 0x03, // flags
1657            0x00, 0x0C, // Length: 12
1658            0x00, 0x00, 0x00, 0x0A, // CCID: 10
1659            0x00, 0x01, // Ns: 1
1660            0x00, 0x02, // Nr: 2
1661        ];
1662
1663        let (header, _) = L2tpv3ControlHeader::from_bytes(&packet).unwrap();
1664        let display = format!("{}", header);
1665        assert!(display.contains("L2TPv3"));
1666        assert!(display.contains("CTRL"));
1667        assert!(display.contains("CCID=10"));
1668        assert!(display.contains("Ns=1"));
1669        assert!(display.contains("Nr=2"));
1670    }
1671
1672    #[test]
1673    fn test_l2tpv3_message_types() {
1674        assert_eq!(L2tpv3MessageType::from(1), L2tpv3MessageType::Sccrq);
1675        assert_eq!(L2tpv3MessageType::from(20), L2tpv3MessageType::Ack);
1676        assert_eq!(L2tpv3MessageType::from(0), L2tpv3MessageType::Zlb);
1677    }
1678
1679    #[test]
1680    fn test_detect_l2tp_version() {
1681        // L2TPv2
1682        let v2_packet = vec![0xC8, 0x02, 0x00, 0x10];
1683        assert_eq!(detect_l2tp_version(&v2_packet), Some(2));
1684
1685        // L2TPv3
1686        let v3_packet = vec![0xC8, 0x03, 0x00, 0x10];
1687        assert_eq!(detect_l2tp_version(&v3_packet), Some(3));
1688
1689        // Too short
1690        assert_eq!(detect_l2tp_version(&[0x00]), None);
1691    }
1692
1693    #[test]
1694    fn test_is_l2tpv3_data_session() {
1695        // Data session (non-zero Session ID)
1696        let data = vec![0x00, 0x00, 0x12, 0x34];
1697        assert!(is_l2tpv3_data_session(&data));
1698
1699        // Control (zero Session ID)
1700        let ctrl = vec![0x00, 0x00, 0x00, 0x00];
1701        assert!(!is_l2tpv3_data_session(&ctrl));
1702
1703        // Too short
1704        assert!(!is_l2tpv3_data_session(&[0x00, 0x00]));
1705    }
1706
1707    #[test]
1708    fn test_l2tp_avp_header_size() {
1709        assert_eq!(std::mem::size_of::<L2tpAvpHeader>(), 6);
1710    }
1711
1712    #[test]
1713    fn test_l2tp_avp_parsing() {
1714        // Message Type AVP (type 0, value = SCCRQ = 1)
1715        let avp_data = vec![
1716            0x80, 0x08, // M=1, H=0, Length=8
1717            0x00, 0x00, // Vendor ID: 0 (IETF)
1718            0x00, 0x00, // Attribute Type: 0 (Message Type)
1719            0x00, 0x01, // Value: SCCRQ
1720        ];
1721
1722        let mut iter = L2tpAvpIter { data: &avp_data };
1723        let avp = iter.next().unwrap();
1724
1725        assert!(avp.header.is_mandatory());
1726        assert!(!avp.header.is_hidden());
1727        assert_eq!(avp.header.length(), 8);
1728        assert_eq!(avp.header.vendor_id(), 0);
1729        assert_eq!(avp.header.attribute_type(), 0);
1730        assert!(avp.is_message_type());
1731        assert_eq!(avp.message_type(), Some(L2tpv2MessageType::Sccrq));
1732        assert_eq!(avp.value.len(), 2);
1733
1734        // No more AVPs
1735        assert!(iter.next().is_none());
1736    }
1737
1738    #[test]
1739    fn test_l2tp_avp_multiple() {
1740        // Two AVPs
1741        let avp_data = vec![
1742            // AVP 1: Message Type
1743            0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
1744            // AVP 2: Protocol Version (type 2)
1745            0x80, 0x08, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00,
1746        ];
1747
1748        let iter = L2tpAvpIter { data: &avp_data };
1749        let avps: Vec<_> = iter.collect();
1750
1751        assert_eq!(avps.len(), 2);
1752        assert_eq!(avps[0].header.attribute_type(), 0);
1753        assert_eq!(avps[1].header.attribute_type(), 2);
1754    }
1755
1756    #[test]
1757    fn test_l2tpv2_full_control_message() {
1758        // Complete SCCRQ message
1759        let packet = vec![
1760            // L2TPv2 Header
1761            0xC8, 0x02, // T=1, L=1, S=1, Ver=2
1762            0x00, 0x00, // Tunnel ID: 0
1763            0x00, 0x00, // Session ID: 0
1764            // Optional fields
1765            0x00, 0x28, // Length: 40
1766            0x00, 0x00, // Ns: 0
1767            0x00, 0x00, // Nr: 0
1768            // AVP: Message Type (SCCRQ)
1769            0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, // AVP: Protocol Version
1770            0x80, 0x08, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00,
1771            // More AVPs would follow...
1772        ];
1773
1774        let (header, payload) = L2tpv2Header::from_bytes(&packet).unwrap();
1775        assert!(header.is_control());
1776        assert_eq!(header.tunnel_id(), 0);
1777        assert_eq!(header.ns(), Some(0));
1778        assert_eq!(header.nr(), Some(0));
1779
1780        // Parse AVPs from payload
1781        let iter = L2tpAvpIter { data: payload };
1782        let avps: Vec<_> = iter.collect();
1783        assert_eq!(avps.len(), 2);
1784    }
1785
1786    #[test]
1787    fn test_l2tpv2_header_opt_display() {
1788        let packet = vec![
1789            0xC8, 0x02, // T=1, L=1, S=1, Ver=2
1790            0x00, 0x0A, // Tunnel ID: 10
1791            0x00, 0x14, // Session ID: 20
1792            0x00, 0x10, // Length: 16
1793            0x00, 0x05, // Ns: 5
1794            0x00, 0x03, // Nr: 3
1795        ];
1796
1797        let (header, _) = L2tpv2Header::from_bytes(&packet).unwrap();
1798        let display = format!("{}", header);
1799        assert!(display.contains("CTRL"));
1800        assert!(display.contains("tunnel=10"));
1801        assert!(display.contains("session=20"));
1802        assert!(display.contains("len=16"));
1803        assert!(display.contains("Ns=5"));
1804        assert!(display.contains("Nr=3"));
1805    }
1806
1807    #[test]
1808    fn test_l2tpv2_data_with_all_flags() {
1809        // Data message with L, S, O, P flags
1810        let packet = vec![
1811            0x4B, 0x02, // L=1, S=1, O=1, P=1, Ver=2
1812            0x00, 0x01, // Tunnel ID
1813            0x00, 0x02, // Session ID
1814            0x00, 0x14, // Length
1815            0x00, 0x01, // Ns
1816            0x00, 0x02, // Nr
1817            0x00, 0x00, // Offset Size
1818            // Payload
1819            0xFF, 0x03,
1820        ];
1821
1822        let (header, _) = L2tpv2Header::from_bytes(&packet).unwrap();
1823        assert!(header.is_data());
1824        assert!(header.has_length());
1825        assert!(header.has_sequence());
1826        assert!(header.has_offset());
1827        assert!(header.has_priority());
1828    }
1829}