packet_strata/packet/tunnel/
gtpv2.rs

1//! GTPv2 (GPRS Tunneling Protocol version 2) parser
2//!
3//! This module implements shallow parsing for GTPv2-C as defined in 3GPP TS 29.274.
4//! GTPv2 is used for control plane signaling in LTE/EPC networks.
5//!
6//! # GTPv2-C Header Format
7//!
8//! ```text
9//!  0                   1                   2                   3
10//!  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
11//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
12//! |  Ver  |P|T|MP |   Spare       |         Message Type          |
13//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
14//! |                         Message Length                        |
15//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
16//! |                         TEID (if T=1)                         |
17//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
18//! |               Sequence Number                 |    Spare      |
19//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
20//! ```
21//!
22//! # Ports
23//!
24//! - GTPv2-C: UDP port 2123
25//!
26//! # Examples
27//!
28//! ## Basic GTPv2-C parsing
29//!
30//! ```
31//! use packet_strata::packet::tunnel::gtpv2::Gtpv2Header;
32//! use packet_strata::packet::HeaderParser;
33//!
34//! // GTPv2-C Echo Request (no TEID)
35//! let packet = vec![
36//!     0x40,        // Version 2, P=0, T=0
37//!     0x01,        // Message type: Echo Request
38//!     0x00, 0x04,  // Length: 4 bytes
39//!     0x00, 0x00, 0x01,  // Sequence number: 1
40//!     0x00,        // Spare
41//! ];
42//!
43//! let (header, _) = Gtpv2Header::from_bytes(&packet).unwrap();
44//! assert_eq!(header.version(), 2);
45//! assert!(!header.has_teid());
46//! assert_eq!(header.message_type(), 1);
47//! ```
48//!
49//! ## GTPv2-C with TEID
50//!
51//! ```
52//! use packet_strata::packet::tunnel::gtpv2::Gtpv2Header;
53//! use packet_strata::packet::HeaderParser;
54//!
55//! // GTPv2-C Create Session Request (with TEID)
56//! let packet = vec![
57//!     0x48,        // Version 2, P=0, T=1
58//!     0x20,        // Message type: Create Session Request
59//!     0x00, 0x08,  // Length: 8 bytes
60//!     0x00, 0x00, 0x00, 0x01,  // TEID: 1
61//!     0x00, 0x00, 0x01,  // Sequence number: 1
62//!     0x00,        // Spare
63//! ];
64//!
65//! let (header, _) = Gtpv2Header::from_bytes(&packet).unwrap();
66//! assert!(header.has_teid());
67//! assert_eq!(header.teid(), Some(1));
68//! assert_eq!(header.sequence_number(), 1);
69//! ```
70
71use std::fmt::{self, Formatter};
72
73use zerocopy::byteorder::{BigEndian, U16};
74use zerocopy::{FromBytes, IntoBytes, Unaligned};
75
76use crate::packet::{HeaderParser, PacketHeader};
77
78/// GTPv2-C standard port
79pub const GTPV2_C_PORT: u16 = 2123;
80
81/// Check if port is GTPv2-C
82#[inline]
83pub fn is_gtpv2_c_port(port: u16) -> bool {
84    port == GTPV2_C_PORT
85}
86
87/// GTPv2 Message Types (commonly used ones)
88#[derive(Debug, Clone, Copy, PartialEq, Eq)]
89#[repr(u8)]
90pub enum Gtpv2MessageType {
91    // Path Management Messages
92    EchoRequest = 1,
93    EchoResponse = 2,
94    VersionNotSupportedIndication = 3,
95
96    // Tunnel Management Messages
97    CreateSessionRequest = 32,
98    CreateSessionResponse = 33,
99    ModifyBearerRequest = 34,
100    ModifyBearerResponse = 35,
101    DeleteSessionRequest = 36,
102    DeleteSessionResponse = 37,
103    ChangeNotificationRequest = 38,
104    ChangeNotificationResponse = 39,
105
106    // Remote UE Report Messages
107    RemoteUeReportNotification = 40,
108    RemoteUeReportAcknowledge = 41,
109
110    // Modify Bearer Command / Failure Indication
111    ModifyBearerCommand = 64,
112    ModifyBearerFailureIndication = 65,
113    DeleteBearerCommand = 66,
114    DeleteBearerFailureIndication = 67,
115    BearerResourceCommand = 68,
116    BearerResourceFailureIndication = 69,
117
118    // Downlink Data Notification
119    DownlinkDataNotification = 176,
120    DownlinkDataNotificationAcknowledge = 177,
121    DownlinkDataNotificationFailureIndication = 70,
122
123    // Create Bearer Messages
124    CreateBearerRequest = 95,
125    CreateBearerResponse = 96,
126    UpdateBearerRequest = 97,
127    UpdateBearerResponse = 98,
128    DeleteBearerRequest = 99,
129    DeleteBearerResponse = 100,
130
131    // Delete PDN Connection Set
132    DeletePdnConnectionSetRequest = 101,
133    DeletePdnConnectionSetResponse = 102,
134
135    // PGW Downlink Triggering
136    PgwDownlinkTriggeringNotification = 103,
137    PgwDownlinkTriggeringAcknowledge = 104,
138
139    // Identification Messages
140    IdentificationRequest = 128,
141    IdentificationResponse = 129,
142
143    // Context Messages
144    ContextRequest = 130,
145    ContextResponse = 131,
146    ContextAcknowledge = 132,
147    ForwardRelocationRequest = 133,
148    ForwardRelocationResponse = 134,
149    ForwardRelocationCompleteNotification = 135,
150    ForwardRelocationCompleteAcknowledge = 136,
151    ForwardAccessContextNotification = 137,
152    ForwardAccessContextAcknowledge = 138,
153    RelocationCancelRequest = 139,
154    RelocationCancelResponse = 140,
155
156    // Configuration Transfer Messages
157    ConfigurationTransferTunnel = 141,
158
159    // Detach Notification
160    DetachNotification = 149,
161    DetachAcknowledge = 150,
162
163    // CS Paging Indication
164    CsPagingIndication = 151,
165    RanInformationRelay = 152,
166
167    // Alert MME / UE Activity Notification
168    AlertMmeNotification = 153,
169    AlertMmeAcknowledge = 154,
170    UeActivityNotification = 155,
171    UeActivityAcknowledge = 156,
172
173    // ISR Status
174    IsrStatusIndication = 157,
175
176    // UE Registration Query
177    UeRegistrationQueryRequest = 158,
178    UeRegistrationQueryResponse = 159,
179
180    // Create Forwarding Tunnel
181    CreateForwardingTunnelRequest = 160,
182    CreateForwardingTunnelResponse = 161,
183
184    // Suspend / Resume Notification
185    SuspendNotification = 162,
186    SuspendAcknowledge = 163,
187    ResumeNotification = 164,
188    ResumeAcknowledge = 165,
189
190    // Create Indirect Data Forwarding Tunnel
191    CreateIndirectDataForwardingTunnelRequest = 166,
192    CreateIndirectDataForwardingTunnelResponse = 167,
193    DeleteIndirectDataForwardingTunnelRequest = 168,
194    DeleteIndirectDataForwardingTunnelResponse = 169,
195
196    // Release Access Bearers
197    ReleaseAccessBearersRequest = 170,
198    ReleaseAccessBearersResponse = 171,
199
200    // Stop Paging Indication
201    StopPagingIndication = 173,
202
203    // Modify Access Bearers
204    ModifyAccessBearersRequest = 211,
205    ModifyAccessBearersResponse = 212,
206
207    // MBMS Session Messages
208    MbmsSessionStartRequest = 231,
209    MbmsSessionStartResponse = 232,
210    MbmsSessionUpdateRequest = 233,
211    MbmsSessionUpdateResponse = 234,
212    MbmsSessionStopRequest = 235,
213    MbmsSessionStopResponse = 236,
214
215    // Unknown message type
216    Unknown = 0,
217}
218
219impl From<u8> for Gtpv2MessageType {
220    fn from(value: u8) -> Self {
221        match value {
222            1 => Gtpv2MessageType::EchoRequest,
223            2 => Gtpv2MessageType::EchoResponse,
224            3 => Gtpv2MessageType::VersionNotSupportedIndication,
225            32 => Gtpv2MessageType::CreateSessionRequest,
226            33 => Gtpv2MessageType::CreateSessionResponse,
227            34 => Gtpv2MessageType::ModifyBearerRequest,
228            35 => Gtpv2MessageType::ModifyBearerResponse,
229            36 => Gtpv2MessageType::DeleteSessionRequest,
230            37 => Gtpv2MessageType::DeleteSessionResponse,
231            38 => Gtpv2MessageType::ChangeNotificationRequest,
232            39 => Gtpv2MessageType::ChangeNotificationResponse,
233            40 => Gtpv2MessageType::RemoteUeReportNotification,
234            41 => Gtpv2MessageType::RemoteUeReportAcknowledge,
235            64 => Gtpv2MessageType::ModifyBearerCommand,
236            65 => Gtpv2MessageType::ModifyBearerFailureIndication,
237            66 => Gtpv2MessageType::DeleteBearerCommand,
238            67 => Gtpv2MessageType::DeleteBearerFailureIndication,
239            68 => Gtpv2MessageType::BearerResourceCommand,
240            69 => Gtpv2MessageType::BearerResourceFailureIndication,
241            70 => Gtpv2MessageType::DownlinkDataNotificationFailureIndication,
242            95 => Gtpv2MessageType::CreateBearerRequest,
243            96 => Gtpv2MessageType::CreateBearerResponse,
244            97 => Gtpv2MessageType::UpdateBearerRequest,
245            98 => Gtpv2MessageType::UpdateBearerResponse,
246            99 => Gtpv2MessageType::DeleteBearerRequest,
247            100 => Gtpv2MessageType::DeleteBearerResponse,
248            101 => Gtpv2MessageType::DeletePdnConnectionSetRequest,
249            102 => Gtpv2MessageType::DeletePdnConnectionSetResponse,
250            103 => Gtpv2MessageType::PgwDownlinkTriggeringNotification,
251            104 => Gtpv2MessageType::PgwDownlinkTriggeringAcknowledge,
252            128 => Gtpv2MessageType::IdentificationRequest,
253            129 => Gtpv2MessageType::IdentificationResponse,
254            130 => Gtpv2MessageType::ContextRequest,
255            131 => Gtpv2MessageType::ContextResponse,
256            132 => Gtpv2MessageType::ContextAcknowledge,
257            133 => Gtpv2MessageType::ForwardRelocationRequest,
258            134 => Gtpv2MessageType::ForwardRelocationResponse,
259            135 => Gtpv2MessageType::ForwardRelocationCompleteNotification,
260            136 => Gtpv2MessageType::ForwardRelocationCompleteAcknowledge,
261            137 => Gtpv2MessageType::ForwardAccessContextNotification,
262            138 => Gtpv2MessageType::ForwardAccessContextAcknowledge,
263            139 => Gtpv2MessageType::RelocationCancelRequest,
264            140 => Gtpv2MessageType::RelocationCancelResponse,
265            141 => Gtpv2MessageType::ConfigurationTransferTunnel,
266            149 => Gtpv2MessageType::DetachNotification,
267            150 => Gtpv2MessageType::DetachAcknowledge,
268            151 => Gtpv2MessageType::CsPagingIndication,
269            152 => Gtpv2MessageType::RanInformationRelay,
270            153 => Gtpv2MessageType::AlertMmeNotification,
271            154 => Gtpv2MessageType::AlertMmeAcknowledge,
272            155 => Gtpv2MessageType::UeActivityNotification,
273            156 => Gtpv2MessageType::UeActivityAcknowledge,
274            157 => Gtpv2MessageType::IsrStatusIndication,
275            158 => Gtpv2MessageType::UeRegistrationQueryRequest,
276            159 => Gtpv2MessageType::UeRegistrationQueryResponse,
277            160 => Gtpv2MessageType::CreateForwardingTunnelRequest,
278            161 => Gtpv2MessageType::CreateForwardingTunnelResponse,
279            162 => Gtpv2MessageType::SuspendNotification,
280            163 => Gtpv2MessageType::SuspendAcknowledge,
281            164 => Gtpv2MessageType::ResumeNotification,
282            165 => Gtpv2MessageType::ResumeAcknowledge,
283            166 => Gtpv2MessageType::CreateIndirectDataForwardingTunnelRequest,
284            167 => Gtpv2MessageType::CreateIndirectDataForwardingTunnelResponse,
285            168 => Gtpv2MessageType::DeleteIndirectDataForwardingTunnelRequest,
286            169 => Gtpv2MessageType::DeleteIndirectDataForwardingTunnelResponse,
287            170 => Gtpv2MessageType::ReleaseAccessBearersRequest,
288            171 => Gtpv2MessageType::ReleaseAccessBearersResponse,
289            173 => Gtpv2MessageType::StopPagingIndication,
290            176 => Gtpv2MessageType::DownlinkDataNotification,
291            177 => Gtpv2MessageType::DownlinkDataNotificationAcknowledge,
292            211 => Gtpv2MessageType::ModifyAccessBearersRequest,
293            212 => Gtpv2MessageType::ModifyAccessBearersResponse,
294            231 => Gtpv2MessageType::MbmsSessionStartRequest,
295            232 => Gtpv2MessageType::MbmsSessionStartResponse,
296            233 => Gtpv2MessageType::MbmsSessionUpdateRequest,
297            234 => Gtpv2MessageType::MbmsSessionUpdateResponse,
298            235 => Gtpv2MessageType::MbmsSessionStopRequest,
299            236 => Gtpv2MessageType::MbmsSessionStopResponse,
300            _ => Gtpv2MessageType::Unknown,
301        }
302    }
303}
304
305impl fmt::Display for Gtpv2MessageType {
306    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
307        match self {
308            Gtpv2MessageType::EchoRequest => write!(f, "Echo Request"),
309            Gtpv2MessageType::EchoResponse => write!(f, "Echo Response"),
310            Gtpv2MessageType::VersionNotSupportedIndication => {
311                write!(f, "Version Not Supported Indication")
312            }
313            Gtpv2MessageType::CreateSessionRequest => write!(f, "Create Session Request"),
314            Gtpv2MessageType::CreateSessionResponse => write!(f, "Create Session Response"),
315            Gtpv2MessageType::ModifyBearerRequest => write!(f, "Modify Bearer Request"),
316            Gtpv2MessageType::ModifyBearerResponse => write!(f, "Modify Bearer Response"),
317            Gtpv2MessageType::DeleteSessionRequest => write!(f, "Delete Session Request"),
318            Gtpv2MessageType::DeleteSessionResponse => write!(f, "Delete Session Response"),
319            Gtpv2MessageType::ChangeNotificationRequest => write!(f, "Change Notification Request"),
320            Gtpv2MessageType::ChangeNotificationResponse => {
321                write!(f, "Change Notification Response")
322            }
323            Gtpv2MessageType::RemoteUeReportNotification => {
324                write!(f, "Remote UE Report Notification")
325            }
326            Gtpv2MessageType::RemoteUeReportAcknowledge => {
327                write!(f, "Remote UE Report Acknowledge")
328            }
329            Gtpv2MessageType::ModifyBearerCommand => write!(f, "Modify Bearer Command"),
330            Gtpv2MessageType::ModifyBearerFailureIndication => {
331                write!(f, "Modify Bearer Failure Indication")
332            }
333            Gtpv2MessageType::DeleteBearerCommand => write!(f, "Delete Bearer Command"),
334            Gtpv2MessageType::DeleteBearerFailureIndication => {
335                write!(f, "Delete Bearer Failure Indication")
336            }
337            Gtpv2MessageType::BearerResourceCommand => write!(f, "Bearer Resource Command"),
338            Gtpv2MessageType::BearerResourceFailureIndication => {
339                write!(f, "Bearer Resource Failure Indication")
340            }
341            Gtpv2MessageType::DownlinkDataNotification => write!(f, "Downlink Data Notification"),
342            Gtpv2MessageType::DownlinkDataNotificationAcknowledge => {
343                write!(f, "Downlink Data Notification Acknowledge")
344            }
345            Gtpv2MessageType::DownlinkDataNotificationFailureIndication => {
346                write!(f, "Downlink Data Notification Failure Indication")
347            }
348            Gtpv2MessageType::CreateBearerRequest => write!(f, "Create Bearer Request"),
349            Gtpv2MessageType::CreateBearerResponse => write!(f, "Create Bearer Response"),
350            Gtpv2MessageType::UpdateBearerRequest => write!(f, "Update Bearer Request"),
351            Gtpv2MessageType::UpdateBearerResponse => write!(f, "Update Bearer Response"),
352            Gtpv2MessageType::DeleteBearerRequest => write!(f, "Delete Bearer Request"),
353            Gtpv2MessageType::DeleteBearerResponse => write!(f, "Delete Bearer Response"),
354            Gtpv2MessageType::DeletePdnConnectionSetRequest => {
355                write!(f, "Delete PDN Connection Set Request")
356            }
357            Gtpv2MessageType::DeletePdnConnectionSetResponse => {
358                write!(f, "Delete PDN Connection Set Response")
359            }
360            Gtpv2MessageType::PgwDownlinkTriggeringNotification => {
361                write!(f, "PGW Downlink Triggering Notification")
362            }
363            Gtpv2MessageType::PgwDownlinkTriggeringAcknowledge => {
364                write!(f, "PGW Downlink Triggering Acknowledge")
365            }
366            Gtpv2MessageType::IdentificationRequest => write!(f, "Identification Request"),
367            Gtpv2MessageType::IdentificationResponse => write!(f, "Identification Response"),
368            Gtpv2MessageType::ContextRequest => write!(f, "Context Request"),
369            Gtpv2MessageType::ContextResponse => write!(f, "Context Response"),
370            Gtpv2MessageType::ContextAcknowledge => write!(f, "Context Acknowledge"),
371            Gtpv2MessageType::ForwardRelocationRequest => write!(f, "Forward Relocation Request"),
372            Gtpv2MessageType::ForwardRelocationResponse => write!(f, "Forward Relocation Response"),
373            Gtpv2MessageType::ForwardRelocationCompleteNotification => {
374                write!(f, "Forward Relocation Complete Notification")
375            }
376            Gtpv2MessageType::ForwardRelocationCompleteAcknowledge => {
377                write!(f, "Forward Relocation Complete Acknowledge")
378            }
379            Gtpv2MessageType::ForwardAccessContextNotification => {
380                write!(f, "Forward Access Context Notification")
381            }
382            Gtpv2MessageType::ForwardAccessContextAcknowledge => {
383                write!(f, "Forward Access Context Acknowledge")
384            }
385            Gtpv2MessageType::RelocationCancelRequest => write!(f, "Relocation Cancel Request"),
386            Gtpv2MessageType::RelocationCancelResponse => write!(f, "Relocation Cancel Response"),
387            Gtpv2MessageType::ConfigurationTransferTunnel => {
388                write!(f, "Configuration Transfer Tunnel")
389            }
390            Gtpv2MessageType::DetachNotification => write!(f, "Detach Notification"),
391            Gtpv2MessageType::DetachAcknowledge => write!(f, "Detach Acknowledge"),
392            Gtpv2MessageType::CsPagingIndication => write!(f, "CS Paging Indication"),
393            Gtpv2MessageType::RanInformationRelay => write!(f, "RAN Information Relay"),
394            Gtpv2MessageType::AlertMmeNotification => write!(f, "Alert MME Notification"),
395            Gtpv2MessageType::AlertMmeAcknowledge => write!(f, "Alert MME Acknowledge"),
396            Gtpv2MessageType::UeActivityNotification => write!(f, "UE Activity Notification"),
397            Gtpv2MessageType::UeActivityAcknowledge => write!(f, "UE Activity Acknowledge"),
398            Gtpv2MessageType::IsrStatusIndication => write!(f, "ISR Status Indication"),
399            Gtpv2MessageType::UeRegistrationQueryRequest => {
400                write!(f, "UE Registration Query Request")
401            }
402            Gtpv2MessageType::UeRegistrationQueryResponse => {
403                write!(f, "UE Registration Query Response")
404            }
405            Gtpv2MessageType::CreateForwardingTunnelRequest => {
406                write!(f, "Create Forwarding Tunnel Request")
407            }
408            Gtpv2MessageType::CreateForwardingTunnelResponse => {
409                write!(f, "Create Forwarding Tunnel Response")
410            }
411            Gtpv2MessageType::SuspendNotification => write!(f, "Suspend Notification"),
412            Gtpv2MessageType::SuspendAcknowledge => write!(f, "Suspend Acknowledge"),
413            Gtpv2MessageType::ResumeNotification => write!(f, "Resume Notification"),
414            Gtpv2MessageType::ResumeAcknowledge => write!(f, "Resume Acknowledge"),
415            Gtpv2MessageType::CreateIndirectDataForwardingTunnelRequest => {
416                write!(f, "Create Indirect Data Forwarding Tunnel Request")
417            }
418            Gtpv2MessageType::CreateIndirectDataForwardingTunnelResponse => {
419                write!(f, "Create Indirect Data Forwarding Tunnel Response")
420            }
421            Gtpv2MessageType::DeleteIndirectDataForwardingTunnelRequest => {
422                write!(f, "Delete Indirect Data Forwarding Tunnel Request")
423            }
424            Gtpv2MessageType::DeleteIndirectDataForwardingTunnelResponse => {
425                write!(f, "Delete Indirect Data Forwarding Tunnel Response")
426            }
427            Gtpv2MessageType::ReleaseAccessBearersRequest => {
428                write!(f, "Release Access Bearers Request")
429            }
430            Gtpv2MessageType::ReleaseAccessBearersResponse => {
431                write!(f, "Release Access Bearers Response")
432            }
433            Gtpv2MessageType::StopPagingIndication => write!(f, "Stop Paging Indication"),
434            Gtpv2MessageType::ModifyAccessBearersRequest => {
435                write!(f, "Modify Access Bearers Request")
436            }
437            Gtpv2MessageType::ModifyAccessBearersResponse => {
438                write!(f, "Modify Access Bearers Response")
439            }
440            Gtpv2MessageType::MbmsSessionStartRequest => write!(f, "MBMS Session Start Request"),
441            Gtpv2MessageType::MbmsSessionStartResponse => write!(f, "MBMS Session Start Response"),
442            Gtpv2MessageType::MbmsSessionUpdateRequest => write!(f, "MBMS Session Update Request"),
443            Gtpv2MessageType::MbmsSessionUpdateResponse => {
444                write!(f, "MBMS Session Update Response")
445            }
446            Gtpv2MessageType::MbmsSessionStopRequest => write!(f, "MBMS Session Stop Request"),
447            Gtpv2MessageType::MbmsSessionStopResponse => write!(f, "MBMS Session Stop Response"),
448            Gtpv2MessageType::Unknown => write!(f, "Unknown"),
449        }
450    }
451}
452
453/// GTPv2 Header structure (fixed 4 bytes, variable depending on T flag)
454///
455/// This is the base GTPv2-C header. The total header size depends on the T flag:
456/// - T=0: 8 bytes (no TEID)
457/// - T=1: 12 bytes (with TEID)
458#[repr(C, packed)]
459#[derive(
460    FromBytes, IntoBytes, Unaligned, Debug, Clone, Copy, zerocopy::KnownLayout, zerocopy::Immutable,
461)]
462pub struct Gtpv2Header {
463    flags: u8,
464    message_type: u8,
465    length: U16<BigEndian>,
466}
467
468impl Gtpv2Header {
469    /// Version field mask (bits 5-7)
470    pub const VERSION_MASK: u8 = 0xE0;
471    pub const VERSION_SHIFT: u8 = 5;
472
473    /// Piggybacking flag (bit 4)
474    pub const FLAG_P: u8 = 0x10;
475
476    /// TEID flag (bit 3): 1 = TEID present
477    pub const FLAG_T: u8 = 0x08;
478
479    /// Message Priority flag (bit 2) - GTPv2 Rel-11+
480    pub const FLAG_MP: u8 = 0x04;
481
482    /// Spare bits mask (bits 0-1)
483    pub const SPARE_MASK: u8 = 0x03;
484
485    /// GTPv2 version number
486    pub const VERSION_2: u8 = 2;
487
488    /// Header length without TEID
489    pub const HEADER_LEN_NO_TEID: usize = 8;
490
491    /// Header length with TEID
492    pub const HEADER_LEN_WITH_TEID: usize = 12;
493
494    #[allow(unused)]
495    const NAME: &'static str = "Gtpv2Header";
496
497    /// Returns the flags byte
498    #[inline]
499    pub fn flags(&self) -> u8 {
500        self.flags
501    }
502
503    /// Returns the GTP version (should be 2)
504    #[inline]
505    pub fn version(&self) -> u8 {
506        (self.flags & Self::VERSION_MASK) >> Self::VERSION_SHIFT
507    }
508
509    /// Returns true if Piggybacking flag is set
510    #[inline]
511    pub fn has_piggybacking(&self) -> bool {
512        self.flags & Self::FLAG_P != 0
513    }
514
515    /// Returns true if TEID flag is set (TEID field is present)
516    #[inline]
517    pub fn has_teid(&self) -> bool {
518        self.flags & Self::FLAG_T != 0
519    }
520
521    /// Returns true if Message Priority flag is set
522    #[inline]
523    pub fn has_message_priority(&self) -> bool {
524        self.flags & Self::FLAG_MP != 0
525    }
526
527    /// Returns the message type
528    #[inline]
529    pub fn message_type(&self) -> u8 {
530        self.message_type
531    }
532
533    /// Returns the message type as enum
534    #[inline]
535    pub fn message_type_enum(&self) -> Gtpv2MessageType {
536        self.message_type.into()
537    }
538
539    /// Returns true if this is an Echo Request
540    #[inline]
541    pub fn is_echo_request(&self) -> bool {
542        self.message_type == 1
543    }
544
545    /// Returns true if this is an Echo Response
546    #[inline]
547    pub fn is_echo_response(&self) -> bool {
548        self.message_type == 2
549    }
550
551    /// Returns the length field (message length excluding first 4 bytes)
552    #[inline]
553    pub fn length(&self) -> u16 {
554        self.length.get()
555    }
556
557    /// Calculate the actual header length based on T flag
558    #[inline]
559    pub fn header_length(&self) -> usize {
560        if self.has_teid() {
561            Self::HEADER_LEN_WITH_TEID
562        } else {
563            Self::HEADER_LEN_NO_TEID
564        }
565    }
566
567    /// Validates the GTPv2 header
568    #[inline]
569    fn is_valid(&self) -> bool {
570        // Version must be 2
571        if self.version() != Self::VERSION_2 {
572            return false;
573        }
574
575        true
576    }
577
578    /// Returns a string representation of active flags
579    pub fn flags_string(&self) -> String {
580        let mut flags = Vec::new();
581
582        if self.has_piggybacking() {
583            flags.push("P");
584        }
585        if self.has_teid() {
586            flags.push("T");
587        }
588        if self.has_message_priority() {
589            flags.push("MP");
590        }
591
592        if flags.is_empty() {
593            "none".to_string()
594        } else {
595            flags.join(",")
596        }
597    }
598}
599
600/// GTPv2 Header with optional fields parsed
601#[derive(Debug, Clone)]
602pub struct Gtpv2HeaderOpt<'a> {
603    pub header: &'a Gtpv2Header,
604    pub raw_options: &'a [u8],
605}
606
607impl<'a> Gtpv2HeaderOpt<'a> {
608    /// Get the TEID if present (when T flag is set)
609    pub fn teid(&self) -> Option<u32> {
610        if !self.header.has_teid() {
611            return None;
612        }
613
614        if self.raw_options.len() < 4 {
615            return None;
616        }
617
618        Some(u32::from_be_bytes([
619            self.raw_options[0],
620            self.raw_options[1],
621            self.raw_options[2],
622            self.raw_options[3],
623        ]))
624    }
625
626    /// Get the sequence number (24 bits)
627    pub fn sequence_number(&self) -> u32 {
628        let offset = if self.header.has_teid() { 4 } else { 0 };
629
630        if self.raw_options.len() < offset + 3 {
631            return 0;
632        }
633
634        u32::from_be_bytes([
635            0,
636            self.raw_options[offset],
637            self.raw_options[offset + 1],
638            self.raw_options[offset + 2],
639        ])
640    }
641
642    /// Get the message priority (4 bits, only valid if MP flag is set)
643    pub fn message_priority(&self) -> Option<u8> {
644        if !self.header.has_message_priority() {
645            return None;
646        }
647
648        let offset = if self.header.has_teid() { 4 } else { 0 };
649
650        if self.raw_options.len() < offset + 4 {
651            return None;
652        }
653
654        // Message priority is in bits 4-7 of the spare byte
655        Some((self.raw_options[offset + 3] >> 4) & 0x0F)
656    }
657}
658
659impl std::ops::Deref for Gtpv2HeaderOpt<'_> {
660    type Target = Gtpv2Header;
661
662    #[inline]
663    fn deref(&self) -> &Self::Target {
664        self.header
665    }
666}
667
668impl PacketHeader for Gtpv2Header {
669    const NAME: &'static str = "Gtpv2Header";
670    /// Inner type - message type
671    type InnerType = u8;
672
673    #[inline]
674    fn inner_type(&self) -> Self::InnerType {
675        self.message_type
676    }
677
678    /// Returns the total header length in bytes (including optional TEID and seq)
679    #[inline]
680    fn total_len(&self, _buf: &[u8]) -> usize {
681        self.header_length()
682    }
683
684    /// Validates the GTPv2 header
685    #[inline]
686    fn is_valid(&self) -> bool {
687        self.is_valid()
688    }
689}
690
691impl HeaderParser for Gtpv2Header {
692    type Output<'a> = Gtpv2HeaderOpt<'a>;
693
694    #[inline]
695    fn into_view<'a>(header: &'a Self, raw_options: &'a [u8]) -> Self::Output<'a> {
696        Gtpv2HeaderOpt {
697            header,
698            raw_options,
699        }
700    }
701}
702
703impl fmt::Display for Gtpv2Header {
704    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
705        write!(
706            f,
707            "GTPv2-C msg={} len={} flags=[{}]",
708            self.message_type_enum(),
709            self.length(),
710            self.flags_string()
711        )
712    }
713}
714
715impl fmt::Display for Gtpv2HeaderOpt<'_> {
716    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
717        write!(f, "GTPv2-C msg={}", self.message_type_enum())?;
718
719        if let Some(teid) = self.teid() {
720            write!(f, " teid=0x{:08x}", teid)?;
721        }
722
723        write!(f, " seq={}", self.sequence_number())?;
724
725        if let Some(prio) = self.message_priority() {
726            write!(f, " prio={}", prio)?;
727        }
728
729        Ok(())
730    }
731}
732
733/// GTPv2 Information Element (IE) header for shallow parsing
734#[repr(C, packed)]
735#[derive(
736    FromBytes, IntoBytes, Unaligned, Debug, Clone, Copy, zerocopy::KnownLayout, zerocopy::Immutable,
737)]
738pub struct Gtpv2IeHeader {
739    ie_type: u8,
740    length: U16<BigEndian>,
741    spare_instance: u8,
742}
743
744impl Gtpv2IeHeader {
745    /// IE Type
746    #[inline]
747    pub fn ie_type(&self) -> u8 {
748        self.ie_type
749    }
750
751    /// IE Length (not including the 4-byte IE header)
752    #[inline]
753    pub fn length(&self) -> u16 {
754        self.length.get()
755    }
756
757    /// Spare bits (bits 4-7)
758    #[inline]
759    pub fn spare(&self) -> u8 {
760        (self.spare_instance >> 4) & 0x0F
761    }
762
763    /// Instance (bits 0-3)
764    #[inline]
765    pub fn instance(&self) -> u8 {
766        self.spare_instance & 0x0F
767    }
768
769    /// Total IE length including header
770    #[inline]
771    pub fn total_length(&self) -> usize {
772        4 + self.length() as usize
773    }
774}
775
776/// Common GTPv2 IE Types
777#[derive(Debug, Clone, Copy, PartialEq, Eq)]
778#[repr(u8)]
779pub enum Gtpv2IeType {
780    Imsi = 1,
781    Cause = 2,
782    Recovery = 3,
783    Apn = 71,
784    Ambr = 72,
785    Ebi = 73,
786    Mei = 75,
787    Msisdn = 76,
788    Indication = 77,
789    Pco = 78,
790    Paa = 79,
791    BearerQos = 80,
792    RatType = 82,
793    ServingNetwork = 83,
794    BearerTft = 84,
795    Tad = 85,
796    Uli = 86,
797    FTeid = 87,
798    BearerContext = 93,
799    ChargingId = 94,
800    ChargingCharacteristics = 95,
801    PdnType = 99,
802    Pti = 100,
803    UeTimeZone = 114,
804    ApnRestriction = 127,
805    SelectionMode = 128,
806    Fqdn = 136,
807    Unknown = 255,
808}
809
810impl From<u8> for Gtpv2IeType {
811    fn from(value: u8) -> Self {
812        match value {
813            1 => Gtpv2IeType::Imsi,
814            2 => Gtpv2IeType::Cause,
815            3 => Gtpv2IeType::Recovery,
816            71 => Gtpv2IeType::Apn,
817            72 => Gtpv2IeType::Ambr,
818            73 => Gtpv2IeType::Ebi,
819            75 => Gtpv2IeType::Mei,
820            76 => Gtpv2IeType::Msisdn,
821            77 => Gtpv2IeType::Indication,
822            78 => Gtpv2IeType::Pco,
823            79 => Gtpv2IeType::Paa,
824            80 => Gtpv2IeType::BearerQos,
825            82 => Gtpv2IeType::RatType,
826            83 => Gtpv2IeType::ServingNetwork,
827            84 => Gtpv2IeType::BearerTft,
828            85 => Gtpv2IeType::Tad,
829            86 => Gtpv2IeType::Uli,
830            87 => Gtpv2IeType::FTeid,
831            93 => Gtpv2IeType::BearerContext,
832            94 => Gtpv2IeType::ChargingId,
833            95 => Gtpv2IeType::ChargingCharacteristics,
834            99 => Gtpv2IeType::PdnType,
835            100 => Gtpv2IeType::Pti,
836            114 => Gtpv2IeType::UeTimeZone,
837            127 => Gtpv2IeType::ApnRestriction,
838            128 => Gtpv2IeType::SelectionMode,
839            136 => Gtpv2IeType::Fqdn,
840            _ => Gtpv2IeType::Unknown,
841        }
842    }
843}
844
845/// Iterator over GTPv2 Information Elements (shallow parsing)
846pub struct Gtpv2IeIter<'a> {
847    data: &'a [u8],
848}
849
850impl<'a> Gtpv2IeIter<'a> {
851    /// Create a new IE iterator from the payload after the GTPv2 header
852    pub fn new(data: &'a [u8]) -> Self {
853        Self { data }
854    }
855}
856
857/// A single GTPv2 IE reference (shallow)
858#[derive(Debug, Clone)]
859pub struct Gtpv2Ie<'a> {
860    /// IE type
861    pub ie_type: u8,
862    /// IE instance
863    pub instance: u8,
864    /// IE value (raw bytes)
865    pub value: &'a [u8],
866}
867
868impl<'a> Iterator for Gtpv2IeIter<'a> {
869    type Item = Gtpv2Ie<'a>;
870
871    fn next(&mut self) -> Option<Self::Item> {
872        // Need at least 4 bytes for IE header
873        if self.data.len() < 4 {
874            return None;
875        }
876
877        let ie_type = self.data[0];
878        let length = u16::from_be_bytes([self.data[1], self.data[2]]) as usize;
879        let instance = self.data[3] & 0x0F;
880
881        let total_len = 4 + length;
882        if self.data.len() < total_len {
883            return None;
884        }
885
886        let value = &self.data[4..total_len];
887
888        let ie = Gtpv2Ie {
889            ie_type,
890            instance,
891            value,
892        };
893
894        self.data = &self.data[total_len..];
895
896        Some(ie)
897    }
898}
899
900#[cfg(test)]
901mod tests {
902    use super::*;
903
904    #[test]
905    fn test_gtpv2_header_size() {
906        assert_eq!(std::mem::size_of::<Gtpv2Header>(), 4);
907        assert_eq!(Gtpv2Header::FIXED_LEN, 4);
908    }
909
910    #[test]
911    fn test_gtpv2_echo_request_no_teid() {
912        // GTPv2-C Echo Request (no TEID)
913        let packet = vec![
914            0x40, // Version 2, P=0, T=0
915            0x01, // Message type: Echo Request
916            0x00, 0x04, // Length: 4 bytes
917            0x00, 0x00, 0x01, // Sequence number: 1
918            0x00, // Spare
919        ];
920
921        let (header, _) = Gtpv2Header::from_bytes(&packet).unwrap();
922        assert_eq!(header.version(), 2);
923        assert!(!header.has_piggybacking());
924        assert!(!header.has_teid());
925        assert!(!header.has_message_priority());
926        assert_eq!(header.message_type(), 1);
927        assert!(header.is_echo_request());
928        assert_eq!(header.length(), 4);
929        assert_eq!(header.header_length(), 8);
930        assert_eq!(header.teid(), None);
931        assert_eq!(header.sequence_number(), 1);
932    }
933
934    #[test]
935    fn test_gtpv2_echo_response_no_teid() {
936        let packet = vec![
937            0x40, // Version 2, P=0, T=0
938            0x02, // Message type: Echo Response
939            0x00, 0x06, // Length: 6 bytes
940            0x00, 0x00, 0x01, // Sequence number: 1
941            0x00, // Spare
942            0x03, 0x00, 0x01, 0x00, // Recovery IE
943        ];
944
945        let (header, payload) = Gtpv2Header::from_bytes(&packet).unwrap();
946        assert!(header.is_echo_response());
947        assert_eq!(header.message_type_enum(), Gtpv2MessageType::EchoResponse);
948        // Payload contains the IE
949        assert_eq!(payload.len(), 4);
950    }
951
952    #[test]
953    fn test_gtpv2_create_session_with_teid() {
954        // GTPv2-C Create Session Request (with TEID)
955        let packet = vec![
956            0x48, // Version 2, P=0, T=1
957            0x20, // Message type: Create Session Request
958            0x00, 0x08, // Length: 8 bytes
959            0x00, 0x00, 0x00, 0x01, // TEID: 1
960            0x00, 0x00, 0x42, // Sequence number: 66
961            0x00, // Spare
962        ];
963
964        let (header, _) = Gtpv2Header::from_bytes(&packet).unwrap();
965        assert_eq!(header.version(), 2);
966        assert!(header.has_teid());
967        assert!(!header.has_piggybacking());
968        assert_eq!(header.message_type(), 0x20);
969        assert_eq!(
970            header.message_type_enum(),
971            Gtpv2MessageType::CreateSessionRequest
972        );
973        assert_eq!(header.length(), 8);
974        assert_eq!(header.header_length(), 12);
975        assert_eq!(header.teid(), Some(1));
976        assert_eq!(header.sequence_number(), 0x42);
977    }
978
979    #[test]
980    fn test_gtpv2_with_piggybacking() {
981        let packet = vec![
982            0x58, // Version 2, P=1, T=1
983            0x21, // Message type: Create Session Response
984            0x00, 0x08, 0x00, 0x00, 0x00, 0x02, // TEID: 2
985            0x00, 0x00, 0x01, // Sequence: 1
986            0x00,
987        ];
988
989        let (header, _) = Gtpv2Header::from_bytes(&packet).unwrap();
990        assert!(header.has_piggybacking());
991        assert!(header.has_teid());
992        assert_eq!(header.teid(), Some(2));
993    }
994
995    #[test]
996    fn test_gtpv2_with_message_priority() {
997        let packet = vec![
998            0x4C, // Version 2, P=0, T=1, MP=1
999            0x20, // Message type
1000            0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x50, // Priority = 5
1001        ];
1002
1003        let (header, _) = Gtpv2Header::from_bytes(&packet).unwrap();
1004        assert!(header.has_message_priority());
1005        assert!(header.has_teid());
1006        assert_eq!(header.message_priority(), Some(5));
1007    }
1008
1009    #[test]
1010    fn test_gtpv2_invalid_version() {
1011        // GTPv1 header (version 1)
1012        let packet = vec![
1013            0x30, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
1014        ];
1015
1016        let result = Gtpv2Header::from_bytes(&packet);
1017        assert!(result.is_err());
1018    }
1019
1020    #[test]
1021    fn test_gtpv2_parsing_too_small() {
1022        let packet = vec![0x40, 0x01]; // Only 2 bytes
1023        let result = Gtpv2Header::from_bytes(&packet);
1024        assert!(result.is_err());
1025    }
1026
1027    #[test]
1028    fn test_gtpv2_flags_string() {
1029        let packet = vec![
1030            0x5C, // Version 2, P=1, T=1, MP=1
1031            0x20, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00,
1032        ];
1033
1034        let (header, _) = Gtpv2Header::from_bytes(&packet).unwrap();
1035        let flags = header.flags_string();
1036        assert!(flags.contains("P"));
1037        assert!(flags.contains("T"));
1038        assert!(flags.contains("MP"));
1039    }
1040
1041    #[test]
1042    fn test_gtpv2_display() {
1043        let packet = vec![
1044            0x48, 0x20, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x42, 0x00,
1045        ];
1046
1047        let (header, _) = Gtpv2Header::from_bytes(&packet).unwrap();
1048        let display = format!("{}", *header);
1049        assert!(display.contains("GTPv2-C"));
1050        assert!(display.contains("Create Session Request"));
1051    }
1052
1053    #[test]
1054    fn test_gtpv2_header_opt_display() {
1055        let packet = vec![
1056            0x48, 0x20, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x42, 0x00,
1057        ];
1058
1059        let (header, _) = Gtpv2Header::from_bytes(&packet).unwrap();
1060        let display = format!("{}", header);
1061        assert!(display.contains("teid=0x00000001"));
1062        assert!(display.contains("seq=66"));
1063    }
1064
1065    #[test]
1066    fn test_gtpv2_message_types() {
1067        assert_eq!(Gtpv2MessageType::from(1), Gtpv2MessageType::EchoRequest);
1068        assert_eq!(Gtpv2MessageType::from(2), Gtpv2MessageType::EchoResponse);
1069        assert_eq!(
1070            Gtpv2MessageType::from(32),
1071            Gtpv2MessageType::CreateSessionRequest
1072        );
1073        assert_eq!(
1074            Gtpv2MessageType::from(36),
1075            Gtpv2MessageType::DeleteSessionRequest
1076        );
1077        assert_eq!(Gtpv2MessageType::from(250), Gtpv2MessageType::Unknown);
1078    }
1079
1080    #[test]
1081    fn test_gtpv2_port() {
1082        assert!(is_gtpv2_c_port(2123));
1083        assert!(!is_gtpv2_c_port(2152));
1084    }
1085
1086    #[test]
1087    fn test_gtpv2_large_teid() {
1088        let packet = vec![
1089            0x48, 0x20, 0x00, 0x08, 0xFF, 0xFF, 0xFF, 0xFF, // TEID: max value
1090            0x00, 0x00, 0x01, 0x00,
1091        ];
1092
1093        let (header, _) = Gtpv2Header::from_bytes(&packet).unwrap();
1094        assert_eq!(header.teid(), Some(0xFFFFFFFF));
1095    }
1096
1097    #[test]
1098    fn test_gtpv2_large_sequence() {
1099        let packet = vec![
1100            0x40, 0x01, 0x00, 0x04, 0xFF, 0xFF, 0xFF, // Sequence: max 24-bit value
1101            0x00,
1102        ];
1103
1104        let (header, _) = Gtpv2Header::from_bytes(&packet).unwrap();
1105        assert_eq!(header.sequence_number(), 0xFFFFFF);
1106    }
1107
1108    #[test]
1109    fn test_gtpv2_delete_session() {
1110        let packet = vec![
1111            0x48, 0x24, // Delete Session Request
1112            0x00, 0x08, 0x00, 0x00, 0x00, 0x05, // TEID: 5
1113            0x00, 0x01, 0x00, 0x00,
1114        ];
1115
1116        let (header, _) = Gtpv2Header::from_bytes(&packet).unwrap();
1117        assert_eq!(
1118            header.message_type_enum(),
1119            Gtpv2MessageType::DeleteSessionRequest
1120        );
1121        assert_eq!(header.teid(), Some(5));
1122    }
1123
1124    #[test]
1125    fn test_gtpv2_ie_iterator() {
1126        // Some IEs after header
1127        let ies = vec![
1128            // Recovery IE (type=3, length=1, instance=0, value=0)
1129            0x03, 0x00, 0x01, 0x00, 0x00,
1130            // Cause IE (type=2, length=2, instance=0, value=0x10, 0x00)
1131            0x02, 0x00, 0x02, 0x00, 0x10, 0x00,
1132        ];
1133
1134        let mut iter = Gtpv2IeIter::new(&ies);
1135
1136        let ie1 = iter.next().unwrap();
1137        assert_eq!(ie1.ie_type, 3); // Recovery
1138        assert_eq!(ie1.instance, 0);
1139        assert_eq!(ie1.value, &[0x00]);
1140
1141        let ie2 = iter.next().unwrap();
1142        assert_eq!(ie2.ie_type, 2); // Cause
1143        assert_eq!(ie2.instance, 0);
1144        assert_eq!(ie2.value, &[0x10, 0x00]);
1145
1146        assert!(iter.next().is_none());
1147    }
1148
1149    #[test]
1150    fn test_gtpv2_ie_types() {
1151        assert_eq!(Gtpv2IeType::from(1), Gtpv2IeType::Imsi);
1152        assert_eq!(Gtpv2IeType::from(2), Gtpv2IeType::Cause);
1153        assert_eq!(Gtpv2IeType::from(87), Gtpv2IeType::FTeid);
1154        assert_eq!(Gtpv2IeType::from(200), Gtpv2IeType::Unknown);
1155    }
1156
1157    #[test]
1158    fn test_gtpv2_ie_header() {
1159        let ie_data: [u8; 4] = [0x57, 0x00, 0x09, 0x01]; // F-TEID IE, length 9, instance 1
1160
1161        let (ie_header_ref, _) =
1162            zerocopy::Ref::<_, Gtpv2IeHeader>::from_prefix(&ie_data[..]).unwrap();
1163        let ie_header = zerocopy::Ref::into_ref(ie_header_ref);
1164        assert_eq!(ie_header.ie_type(), 0x57);
1165        assert_eq!(ie_header.length(), 9);
1166        assert_eq!(ie_header.instance(), 1);
1167        assert_eq!(ie_header.spare(), 0);
1168        assert_eq!(ie_header.total_length(), 13);
1169    }
1170
1171    #[test]
1172    fn test_gtpv2_modify_bearer() {
1173        let packet = vec![
1174            0x48, 0x22, // Modify Bearer Request
1175            0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x05, 0x00,
1176        ];
1177
1178        let (header, _) = Gtpv2Header::from_bytes(&packet).unwrap();
1179        assert_eq!(
1180            header.message_type_enum(),
1181            Gtpv2MessageType::ModifyBearerRequest
1182        );
1183    }
1184
1185    #[test]
1186    fn test_gtpv2_version_not_supported() {
1187        let packet = vec![
1188            0x40, 0x03, // Version Not Supported Indication
1189            0x00, 0x04, 0x00, 0x00, 0x01, 0x00,
1190        ];
1191
1192        let (header, _) = Gtpv2Header::from_bytes(&packet).unwrap();
1193        assert_eq!(
1194            header.message_type_enum(),
1195            Gtpv2MessageType::VersionNotSupportedIndication
1196        );
1197    }
1198}