1use std::fmt::{self, Formatter};
109
110use zerocopy::byteorder::{BigEndian, U16, U32};
111use zerocopy::{FromBytes, IntoBytes, Unaligned};
112
113use crate::packet::{HeaderParser, PacketHeader, PacketHeaderError};
114
115pub const L2TP_PORT: u16 = 1701;
117
118pub const L2TPV3_IP_PROTO: u8 = 115;
120
121#[inline]
123pub fn is_l2tp_port(port: u16) -> bool {
124 port == L2TP_PORT
125}
126
127#[inline]
129pub fn is_l2tpv3_proto(proto: u8) -> bool {
130 proto == L2TPV3_IP_PROTO
131}
132
133#[derive(Debug, Clone, Copy, PartialEq, Eq)]
135pub enum L2tpv2MessageType {
136 Sccrq,
138 Sccrp,
140 Scccn,
142 StopCcn,
144 Hello,
146 Ocrq,
148 Ocrp,
150 Occn,
152 Icrq,
154 Icrp,
156 Iccn,
158 Cdn,
160 Wen,
162 Sli,
164 Zlb,
166 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#[derive(Debug, Clone, Copy, PartialEq, Eq)]
218pub enum L2tpv3MessageType {
219 Sccrq,
221 Sccrp,
223 Scccn,
225 StopCcn,
227 Hello,
229 Icrq,
231 Icrp,
233 Iccn,
235 Ocrq,
237 Ocrp,
239 Occn,
241 Cdn,
243 Sli,
245 Ack,
247 Zlb,
249 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#[derive(Debug, Clone, Copy, PartialEq, Eq)]
301pub enum L2tpAvpType {
302 MessageType,
304 ResultCode,
306 ProtocolVersion,
308 FramingCapabilities,
310 BearerCapabilities,
312 TieBreaker,
314 FirmwareRevision,
316 HostName,
318 VendorName,
320 AssignedTunnelId,
322 ReceiveWindowSize,
324 Challenge,
326 Q931CauseCode,
328 ChallengeResponse,
330 AssignedSessionId,
332 CallSerialNumber,
334 MinimumBps,
336 MaximumBps,
338 BearerType,
340 FramingType,
342 CalledNumber,
344 CallingNumber,
346 SubAddress,
348 TxConnectSpeed,
350 PhysicalChannelId,
352 InitialReceivedLcpConfreq,
354 LastSentLcpConfreq,
356 LastReceivedLcpConfreq,
358 ProxyAuthenType,
360 ProxyAuthenName,
362 ProxyAuthenChallenge,
364 ProxyAuthenId,
366 ProxyAuthenResponse,
368 CallErrors,
370 Accm,
372 RandomVector,
374 PrivateGroupId,
376 RxConnectSpeed,
378 SequencingRequired,
380 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#[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 pub const FLAG_TYPE: u16 = 0x8000;
500 pub const FLAG_LENGTH: u16 = 0x4000;
502 pub const FLAG_SEQUENCE: u16 = 0x0800;
504 pub const FLAG_OFFSET: u16 = 0x0200;
506 pub const FLAG_PRIORITY: u16 = 0x0100;
508
509 pub const VERSION_MASK: u16 = 0x000F;
511
512 pub const VERSION_2: u16 = 0x0002;
514
515 pub const MIN_HEADER_LEN: usize = 6;
517
518 pub const LENGTH_FIELD_SIZE: usize = 2;
520
521 pub const SEQUENCE_FIELDS_SIZE: usize = 4;
523
524 pub const OFFSET_FIELD_SIZE: usize = 2;
526
527 #[allow(unused)]
528 const NAME: &'static str = "L2TPv2";
529
530 #[inline]
532 pub fn flags_version(&self) -> u16 {
533 self.flags_version.get()
534 }
535
536 #[inline]
538 pub fn version(&self) -> u16 {
539 self.flags_version.get() & Self::VERSION_MASK
540 }
541
542 #[inline]
544 pub fn is_control(&self) -> bool {
545 (self.flags_version.get() & Self::FLAG_TYPE) != 0
546 }
547
548 #[inline]
550 pub fn is_data(&self) -> bool {
551 !self.is_control()
552 }
553
554 #[inline]
556 pub fn has_length(&self) -> bool {
557 (self.flags_version.get() & Self::FLAG_LENGTH) != 0
558 }
559
560 #[inline]
562 pub fn has_sequence(&self) -> bool {
563 (self.flags_version.get() & Self::FLAG_SEQUENCE) != 0
564 }
565
566 #[inline]
568 pub fn has_offset(&self) -> bool {
569 (self.flags_version.get() & Self::FLAG_OFFSET) != 0
570 }
571
572 #[inline]
574 pub fn has_priority(&self) -> bool {
575 (self.flags_version.get() & Self::FLAG_PRIORITY) != 0
576 }
577
578 #[inline]
580 pub fn tunnel_id(&self) -> u16 {
581 self.tunnel_id.get()
582 }
583
584 #[inline]
586 pub fn session_id(&self) -> u16 {
587 self.session_id.get()
588 }
589
590 #[inline]
592 pub fn has_optional_fields(&self) -> bool {
593 self.has_length() || self.has_sequence() || self.has_offset()
594 }
595
596 #[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 fn is_valid(&self) -> bool {
614 if self.version() != Self::VERSION_2 {
616 return false;
617 }
618 if self.is_control() && (!self.has_length() || !self.has_sequence()) {
620 return false;
621 }
622 true
623 }
624
625 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#[derive(Debug, Clone)]
653pub struct L2tpv2HeaderOpt<'a> {
654 pub header: &'a L2tpv2Header,
656 pub raw_options: &'a [u8],
658}
659
660impl<'a> L2tpv2HeaderOpt<'a> {
661 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 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 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 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 pub fn avps(&self) -> L2tpAvpIter<'a> {
733 if !self.header.is_control() {
734 return L2tpAvpIter { data: &[] };
735 }
736 L2tpAvpIter { data: &[] } }
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#[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 pub const FLAG_MANDATORY: u16 = 0x8000;
764 pub const FLAG_HIDDEN: u16 = 0x4000;
766 pub const LENGTH_MASK: u16 = 0x03FF;
768
769 pub const HEADER_SIZE: usize = 6;
771
772 #[inline]
774 pub fn is_mandatory(&self) -> bool {
775 (self.flags_length.get() & Self::FLAG_MANDATORY) != 0
776 }
777
778 #[inline]
780 pub fn is_hidden(&self) -> bool {
781 (self.flags_length.get() & Self::FLAG_HIDDEN) != 0
782 }
783
784 #[inline]
786 pub fn length(&self) -> u16 {
787 self.flags_length.get() & Self::LENGTH_MASK
788 }
789
790 #[inline]
792 pub fn vendor_id(&self) -> u16 {
793 self.vendor_id.get()
794 }
795
796 #[inline]
798 pub fn attribute_type(&self) -> u16 {
799 self.attribute_type.get()
800 }
801
802 #[inline]
804 pub fn attribute_type_enum(&self) -> L2tpAvpType {
805 L2tpAvpType::from(self.attribute_type.get())
806 }
807
808 #[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#[derive(Debug, Clone)]
818pub struct L2tpAvp<'a> {
819 pub header: &'a L2tpAvpHeader,
821 pub value: &'a [u8],
823}
824
825impl<'a> L2tpAvp<'a> {
826 #[inline]
828 pub fn is_message_type(&self) -> bool {
829 self.header.vendor_id() == 0 && self.header.attribute_type() == 0
830 }
831
832 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#[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 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 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#[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 pub const MIN_HEADER_LEN: usize = 4;
979
980 #[allow(unused)]
981 const NAME: &'static str = "L2TPv3-Session";
982
983 #[inline]
985 pub fn session_id(&self) -> u32 {
986 self.session_id.get()
987 }
988
989 #[inline]
992 fn is_valid(&self) -> bool {
993 self.session_id.get() != 0
994 }
995}
996
997#[derive(Debug, Clone)]
999pub struct L2tpv3SessionHeaderCookie<'a> {
1000 pub header: &'a L2tpv3SessionHeader,
1002 pub cookie: &'a [u8],
1004}
1005
1006impl<'a> L2tpv3SessionHeaderCookie<'a> {
1007 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 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 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 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#[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 pub const FLAG_TYPE: u16 = 0x8000;
1157 pub const FLAG_LENGTH: u16 = 0x4000;
1159 pub const FLAG_SEQUENCE: u16 = 0x0800;
1161
1162 pub const VERSION_MASK: u16 = 0x000F;
1164
1165 pub const VERSION_3: u16 = 0x0003;
1167
1168 pub const HEADER_LEN: usize = 12;
1170
1171 #[allow(unused)]
1172 const NAME: &'static str = "L2TPv3-Control";
1173
1174 #[inline]
1176 pub fn flags_version(&self) -> u16 {
1177 self.flags_version.get()
1178 }
1179
1180 #[inline]
1182 pub fn version(&self) -> u16 {
1183 self.flags_version.get() & Self::VERSION_MASK
1184 }
1185
1186 #[inline]
1188 pub fn is_control(&self) -> bool {
1189 (self.flags_version.get() & Self::FLAG_TYPE) != 0
1190 }
1191
1192 #[inline]
1194 pub fn has_length(&self) -> bool {
1195 (self.flags_version.get() & Self::FLAG_LENGTH) != 0
1196 }
1197
1198 #[inline]
1200 pub fn has_sequence(&self) -> bool {
1201 (self.flags_version.get() & Self::FLAG_SEQUENCE) != 0
1202 }
1203
1204 #[inline]
1206 pub fn length(&self) -> u16 {
1207 self.length.get()
1208 }
1209
1210 #[inline]
1212 pub fn control_connection_id(&self) -> u32 {
1213 self.control_connection_id.get()
1214 }
1215
1216 #[inline]
1218 pub fn ns(&self) -> u16 {
1219 self.ns.get()
1220 }
1221
1222 #[inline]
1224 pub fn nr(&self) -> u16 {
1225 self.nr.get()
1226 }
1227
1228 fn is_valid(&self) -> bool {
1230 if self.version() != Self::VERSION_3 {
1232 return false;
1233 }
1234 if !self.is_control() || !self.has_length() || !self.has_sequence() {
1236 return false;
1237 }
1238 true
1239 }
1240
1241 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
1302pub 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
1311pub 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 let packet = vec![
1336 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 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 let packet = vec![
1360 0xC8, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x02, 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 let packet = vec![
1387 0x02, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x04, 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 let packet = vec![
1405 0x01, 0x02, 0x00, 0x01, 0x00, 0x02, 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 let packet = vec![
1421 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, ];
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 let packet = vec![
1434 0x88, 0x02, 0x00, 0x01, 0x00, 0x00, ];
1438
1439 let result = L2tpv2Header::from_bytes(&packet);
1440 assert!(result.is_err());
1441 }
1442
1443 #[test]
1444 fn test_l2tpv2_flags_string() {
1445 let packet = vec![
1447 0xC9, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, ];
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, 0x00, 0x0A, 0x00, 0x14, 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 #[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 let packet = vec![
1541 0x00, 0x00, 0x12, 0x34, 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, 0xDE, 0xAD, 0xBE, 0xEF, 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, 0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE, 0xBA, 0xBE, 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 let packet = vec![
1586 0x00, 0x00, 0x00, 0x00, 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, 0x12, 0x34, 0x56, 0x78, ];
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 let packet = vec![
1617 0xC8, 0x03, 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x05, 0x00, 0x04, 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 let packet = vec![
1642 0xC8, 0x02, 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x05, 0x00, 0x04, ];
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, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x01, 0x00, 0x02, ];
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 let v2_packet = vec![0xC8, 0x02, 0x00, 0x10];
1683 assert_eq!(detect_l2tp_version(&v2_packet), Some(2));
1684
1685 let v3_packet = vec![0xC8, 0x03, 0x00, 0x10];
1687 assert_eq!(detect_l2tp_version(&v3_packet), Some(3));
1688
1689 assert_eq!(detect_l2tp_version(&[0x00]), None);
1691 }
1692
1693 #[test]
1694 fn test_is_l2tpv3_data_session() {
1695 let data = vec![0x00, 0x00, 0x12, 0x34];
1697 assert!(is_l2tpv3_data_session(&data));
1698
1699 let ctrl = vec![0x00, 0x00, 0x00, 0x00];
1701 assert!(!is_l2tpv3_data_session(&ctrl));
1702
1703 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 let avp_data = vec![
1716 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, ];
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 assert!(iter.next().is_none());
1736 }
1737
1738 #[test]
1739 fn test_l2tp_avp_multiple() {
1740 let avp_data = vec![
1742 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
1744 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 let packet = vec![
1760 0xC8, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x08, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00,
1771 ];
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 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, 0x00, 0x0A, 0x00, 0x14, 0x00, 0x10, 0x00, 0x05, 0x00, 0x03, ];
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 let packet = vec![
1811 0x4B, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x14, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 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}