1use std::fmt::{self, Formatter};
72
73use zerocopy::byteorder::{BigEndian, U16};
74use zerocopy::{FromBytes, IntoBytes, Unaligned};
75
76use crate::packet::{HeaderParser, PacketHeader};
77
78pub const GTPV2_C_PORT: u16 = 2123;
80
81#[inline]
83pub fn is_gtpv2_c_port(port: u16) -> bool {
84 port == GTPV2_C_PORT
85}
86
87#[derive(Debug, Clone, Copy, PartialEq, Eq)]
89#[repr(u8)]
90pub enum Gtpv2MessageType {
91 EchoRequest = 1,
93 EchoResponse = 2,
94 VersionNotSupportedIndication = 3,
95
96 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 RemoteUeReportNotification = 40,
108 RemoteUeReportAcknowledge = 41,
109
110 ModifyBearerCommand = 64,
112 ModifyBearerFailureIndication = 65,
113 DeleteBearerCommand = 66,
114 DeleteBearerFailureIndication = 67,
115 BearerResourceCommand = 68,
116 BearerResourceFailureIndication = 69,
117
118 DownlinkDataNotification = 176,
120 DownlinkDataNotificationAcknowledge = 177,
121 DownlinkDataNotificationFailureIndication = 70,
122
123 CreateBearerRequest = 95,
125 CreateBearerResponse = 96,
126 UpdateBearerRequest = 97,
127 UpdateBearerResponse = 98,
128 DeleteBearerRequest = 99,
129 DeleteBearerResponse = 100,
130
131 DeletePdnConnectionSetRequest = 101,
133 DeletePdnConnectionSetResponse = 102,
134
135 PgwDownlinkTriggeringNotification = 103,
137 PgwDownlinkTriggeringAcknowledge = 104,
138
139 IdentificationRequest = 128,
141 IdentificationResponse = 129,
142
143 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 ConfigurationTransferTunnel = 141,
158
159 DetachNotification = 149,
161 DetachAcknowledge = 150,
162
163 CsPagingIndication = 151,
165 RanInformationRelay = 152,
166
167 AlertMmeNotification = 153,
169 AlertMmeAcknowledge = 154,
170 UeActivityNotification = 155,
171 UeActivityAcknowledge = 156,
172
173 IsrStatusIndication = 157,
175
176 UeRegistrationQueryRequest = 158,
178 UeRegistrationQueryResponse = 159,
179
180 CreateForwardingTunnelRequest = 160,
182 CreateForwardingTunnelResponse = 161,
183
184 SuspendNotification = 162,
186 SuspendAcknowledge = 163,
187 ResumeNotification = 164,
188 ResumeAcknowledge = 165,
189
190 CreateIndirectDataForwardingTunnelRequest = 166,
192 CreateIndirectDataForwardingTunnelResponse = 167,
193 DeleteIndirectDataForwardingTunnelRequest = 168,
194 DeleteIndirectDataForwardingTunnelResponse = 169,
195
196 ReleaseAccessBearersRequest = 170,
198 ReleaseAccessBearersResponse = 171,
199
200 StopPagingIndication = 173,
202
203 ModifyAccessBearersRequest = 211,
205 ModifyAccessBearersResponse = 212,
206
207 MbmsSessionStartRequest = 231,
209 MbmsSessionStartResponse = 232,
210 MbmsSessionUpdateRequest = 233,
211 MbmsSessionUpdateResponse = 234,
212 MbmsSessionStopRequest = 235,
213 MbmsSessionStopResponse = 236,
214
215 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#[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 pub const VERSION_MASK: u8 = 0xE0;
471 pub const VERSION_SHIFT: u8 = 5;
472
473 pub const FLAG_P: u8 = 0x10;
475
476 pub const FLAG_T: u8 = 0x08;
478
479 pub const FLAG_MP: u8 = 0x04;
481
482 pub const SPARE_MASK: u8 = 0x03;
484
485 pub const VERSION_2: u8 = 2;
487
488 pub const HEADER_LEN_NO_TEID: usize = 8;
490
491 pub const HEADER_LEN_WITH_TEID: usize = 12;
493
494 #[allow(unused)]
495 const NAME: &'static str = "Gtpv2Header";
496
497 #[inline]
499 pub fn flags(&self) -> u8 {
500 self.flags
501 }
502
503 #[inline]
505 pub fn version(&self) -> u8 {
506 (self.flags & Self::VERSION_MASK) >> Self::VERSION_SHIFT
507 }
508
509 #[inline]
511 pub fn has_piggybacking(&self) -> bool {
512 self.flags & Self::FLAG_P != 0
513 }
514
515 #[inline]
517 pub fn has_teid(&self) -> bool {
518 self.flags & Self::FLAG_T != 0
519 }
520
521 #[inline]
523 pub fn has_message_priority(&self) -> bool {
524 self.flags & Self::FLAG_MP != 0
525 }
526
527 #[inline]
529 pub fn message_type(&self) -> u8 {
530 self.message_type
531 }
532
533 #[inline]
535 pub fn message_type_enum(&self) -> Gtpv2MessageType {
536 self.message_type.into()
537 }
538
539 #[inline]
541 pub fn is_echo_request(&self) -> bool {
542 self.message_type == 1
543 }
544
545 #[inline]
547 pub fn is_echo_response(&self) -> bool {
548 self.message_type == 2
549 }
550
551 #[inline]
553 pub fn length(&self) -> u16 {
554 self.length.get()
555 }
556
557 #[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 #[inline]
569 fn is_valid(&self) -> bool {
570 if self.version() != Self::VERSION_2 {
572 return false;
573 }
574
575 true
576 }
577
578 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#[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 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 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 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 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 type InnerType = u8;
672
673 #[inline]
674 fn inner_type(&self) -> Self::InnerType {
675 self.message_type
676 }
677
678 #[inline]
680 fn total_len(&self, _buf: &[u8]) -> usize {
681 self.header_length()
682 }
683
684 #[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#[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 #[inline]
747 pub fn ie_type(&self) -> u8 {
748 self.ie_type
749 }
750
751 #[inline]
753 pub fn length(&self) -> u16 {
754 self.length.get()
755 }
756
757 #[inline]
759 pub fn spare(&self) -> u8 {
760 (self.spare_instance >> 4) & 0x0F
761 }
762
763 #[inline]
765 pub fn instance(&self) -> u8 {
766 self.spare_instance & 0x0F
767 }
768
769 #[inline]
771 pub fn total_length(&self) -> usize {
772 4 + self.length() as usize
773 }
774}
775
776#[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
845pub struct Gtpv2IeIter<'a> {
847 data: &'a [u8],
848}
849
850impl<'a> Gtpv2IeIter<'a> {
851 pub fn new(data: &'a [u8]) -> Self {
853 Self { data }
854 }
855}
856
857#[derive(Debug, Clone)]
859pub struct Gtpv2Ie<'a> {
860 pub ie_type: u8,
862 pub instance: u8,
864 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 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 let packet = vec![
914 0x40, 0x01, 0x00, 0x04, 0x00, 0x00, 0x01, 0x00, ];
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, 0x02, 0x00, 0x06, 0x00, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, ];
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 assert_eq!(payload.len(), 4);
950 }
951
952 #[test]
953 fn test_gtpv2_create_session_with_teid() {
954 let packet = vec![
956 0x48, 0x20, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x42, 0x00, ];
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, 0x21, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x01, 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, 0x20, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x50, ];
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 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]; 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, 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, 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, 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, 0x00, 0x08, 0x00, 0x00, 0x00, 0x05, 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 let ies = vec![
1128 0x03, 0x00, 0x01, 0x00, 0x00,
1130 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); 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); 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]; 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, 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, 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}