1use core::num::NonZeroU8;
8use core::time::Duration;
9
10use net_types::ip::{Ipv6, Ipv6Addr};
11use zerocopy::byteorder::network_endian::{U16, U32};
12use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout, SplitByteSlice, Unaligned};
13
14use crate::icmp::{IcmpIpExt, IcmpPacket, IcmpPacketRaw, IcmpZeroCode};
15use crate::utils::NonZeroDuration;
16
17#[allow(missing_docs)]
19#[derive(Debug)]
20pub enum NdpPacket<B: SplitByteSlice> {
21 RouterSolicitation(IcmpPacket<Ipv6, B, RouterSolicitation>),
22 RouterAdvertisement(IcmpPacket<Ipv6, B, RouterAdvertisement>),
23 NeighborSolicitation(IcmpPacket<Ipv6, B, NeighborSolicitation>),
24 NeighborAdvertisement(IcmpPacket<Ipv6, B, NeighborAdvertisement>),
25 Redirect(IcmpPacket<Ipv6, B, Redirect>),
26}
27
28#[allow(missing_docs)]
30#[derive(Debug)]
31pub enum NdpPacketRaw<B: SplitByteSlice> {
32 RouterSolicitation(IcmpPacketRaw<Ipv6, B, RouterSolicitation>),
33 RouterAdvertisement(IcmpPacketRaw<Ipv6, B, RouterAdvertisement>),
34 NeighborSolicitation(IcmpPacketRaw<Ipv6, B, NeighborSolicitation>),
35 NeighborAdvertisement(IcmpPacketRaw<Ipv6, B, NeighborAdvertisement>),
36 Redirect(IcmpPacketRaw<Ipv6, B, Redirect>),
37}
38
39#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
41pub enum NonZeroNdpLifetime {
42 Finite(NonZeroDuration),
50
51 Infinite,
53}
54
55impl NonZeroNdpLifetime {
56 pub fn from_u32_with_infinite(lifetime: u32) -> Option<NonZeroNdpLifetime> {
59 match lifetime {
77 u32::MAX => Some(NonZeroNdpLifetime::Infinite),
78 finite => NonZeroDuration::new(Duration::from_secs(finite.into()))
79 .map(NonZeroNdpLifetime::Finite),
80 }
81 }
82
83 pub fn min_finite_duration(self, other: NonZeroDuration) -> NonZeroDuration {
85 match self {
86 NonZeroNdpLifetime::Finite(lifetime) => core::cmp::min(lifetime, other),
87 NonZeroNdpLifetime::Infinite => other,
88 }
89 }
90}
91
92pub type Options<B> = packet::records::options::Options<B, options::NdpOptionsImpl>;
98
99pub type OptionSequenceBuilder<'a, I> =
105 packet::records::options::OptionSequenceBuilder<options::NdpOptionBuilder<'a>, I>;
106
107#[derive(
109 Copy,
110 Clone,
111 Default,
112 Debug,
113 KnownLayout,
114 FromBytes,
115 IntoBytes,
116 Immutable,
117 Unaligned,
118 PartialEq,
119 Eq,
120)]
121#[repr(C)]
122pub struct RouterSolicitation {
123 _reserved: [u8; 4],
124}
125
126impl_icmp_message!(Ipv6, RouterSolicitation, RouterSolicitation, IcmpZeroCode, Options<B>);
127
128#[allow(missing_docs)]
132#[derive(Copy, Clone, Debug, PartialEq, Eq)]
133pub enum RoutePreference {
134 High,
140 Medium,
141 Low,
142}
143
144impl Default for RoutePreference {
145 fn default() -> RoutePreference {
146 RoutePreference::Medium
156 }
157}
158
159impl From<RoutePreference> for u8 {
160 fn from(v: RoutePreference) -> u8 {
161 match v {
171 RoutePreference::High => 0b01,
172 RoutePreference::Medium => 0b00,
173 RoutePreference::Low => 0b11,
174 }
175 }
176}
177
178impl TryFrom<u8> for RoutePreference {
179 type Error = ();
180
181 fn try_from(v: u8) -> Result<Self, Self::Error> {
182 match v {
192 0b01 => Ok(RoutePreference::High),
193 0b00 => Ok(RoutePreference::Medium),
194 0b11 => Ok(RoutePreference::Low),
195 _ => Err(()),
196 }
197 }
198}
199
200#[derive(
202 Copy, Clone, Debug, KnownLayout, FromBytes, IntoBytes, Immutable, Unaligned, PartialEq, Eq,
203)]
204#[repr(C)]
205pub struct RouterAdvertisement {
206 current_hop_limit: u8,
207 configuration_mo: u8,
208 router_lifetime: U16,
209 reachable_time: U32,
210 retransmit_timer: U32,
211}
212
213impl_icmp_message!(Ipv6, RouterAdvertisement, RouterAdvertisement, IcmpZeroCode, Options<B>);
214
215impl RouterAdvertisement {
216 const MANAGED_FLAG: u8 = 0x80;
224
225 const OTHER_CONFIGURATION_FLAG: u8 = 0x40;
231
232 const DEFAULT_ROUTER_PREFERENCE_SHIFT: u8 = 3;
256 const DEFAULT_ROUTER_PREFERENCE_MASK: u8 = 0b11 << Self::DEFAULT_ROUTER_PREFERENCE_SHIFT;
257
258 pub fn new(
262 current_hop_limit: u8,
263 managed_flag: bool,
264 other_config_flag: bool,
265 router_lifetime: u16,
266 reachable_time: u32,
267 retransmit_timer: u32,
268 ) -> Self {
269 Self::with_prf(
270 current_hop_limit,
271 managed_flag,
272 other_config_flag,
273 RoutePreference::default(),
274 router_lifetime,
275 reachable_time,
276 retransmit_timer,
277 )
278 }
279
280 pub fn with_prf(
282 current_hop_limit: u8,
283 managed_flag: bool,
284 other_config_flag: bool,
285 preference: RoutePreference,
286 router_lifetime: u16,
287 reachable_time: u32,
288 retransmit_timer: u32,
289 ) -> Self {
290 let mut configuration_mo = 0;
291
292 if managed_flag {
293 configuration_mo |= Self::MANAGED_FLAG;
294 }
295
296 if other_config_flag {
297 configuration_mo |= Self::OTHER_CONFIGURATION_FLAG;
298 }
299
300 configuration_mo |= (u8::from(preference) << Self::DEFAULT_ROUTER_PREFERENCE_SHIFT)
301 & Self::DEFAULT_ROUTER_PREFERENCE_MASK;
302
303 Self {
304 current_hop_limit,
305 configuration_mo,
306 router_lifetime: U16::new(router_lifetime),
307 reachable_time: U32::new(reachable_time),
308 retransmit_timer: U32::new(retransmit_timer),
309 }
310 }
311
312 pub fn current_hop_limit(&self) -> Option<NonZeroU8> {
316 NonZeroU8::new(self.current_hop_limit)
317 }
318
319 pub fn router_lifetime(&self) -> Option<NonZeroDuration> {
324 NonZeroDuration::new(Duration::from_secs(self.router_lifetime.get().into()))
327 }
328
329 pub fn reachable_time(&self) -> Option<NonZeroDuration> {
333 NonZeroDuration::new(Duration::from_millis(self.reachable_time.get().into()))
336 }
337
338 pub fn retransmit_timer(&self) -> Option<NonZeroDuration> {
342 NonZeroDuration::new(Duration::from_millis(self.retransmit_timer.get().into()))
345 }
346
347 pub fn preference(&self) -> RoutePreference {
349 let preference = (self.configuration_mo & Self::DEFAULT_ROUTER_PREFERENCE_MASK)
350 >> Self::DEFAULT_ROUTER_PREFERENCE_SHIFT;
351 RoutePreference::try_from(preference).unwrap_or_default()
355 }
356}
357
358#[derive(
360 Copy, Clone, Debug, KnownLayout, FromBytes, IntoBytes, Immutable, Unaligned, PartialEq, Eq,
361)]
362#[repr(C)]
363pub struct NeighborSolicitation {
364 _reserved: [u8; 4],
365 target_address: Ipv6Addr,
366}
367
368impl_icmp_message!(Ipv6, NeighborSolicitation, NeighborSolicitation, IcmpZeroCode, Options<B>);
369
370impl NeighborSolicitation {
371 pub fn new(target_address: Ipv6Addr) -> Self {
374 Self { _reserved: [0; 4], target_address }
375 }
376
377 pub fn target_address(&self) -> &Ipv6Addr {
379 &self.target_address
380 }
381}
382
383#[derive(
385 Copy, Clone, Debug, KnownLayout, FromBytes, IntoBytes, Immutable, Unaligned, PartialEq, Eq,
386)]
387#[repr(C)]
388pub struct NeighborAdvertisement {
389 flags_rso: u8,
390 _reserved: [u8; 3],
391 target_address: Ipv6Addr,
392}
393
394impl_icmp_message!(Ipv6, NeighborAdvertisement, NeighborAdvertisement, IcmpZeroCode, Options<B>);
395
396impl NeighborAdvertisement {
397 const FLAG_ROUTER: u8 = 0x80;
403
404 const FLAG_SOLICITED: u8 = 0x40;
412
413 const FLAG_OVERRIDE: u8 = 0x20;
424
425 pub fn new(
428 router_flag: bool,
429 solicited_flag: bool,
430 override_flag: bool,
431 target_address: Ipv6Addr,
432 ) -> Self {
433 let mut flags_rso = 0;
434
435 if router_flag {
436 flags_rso |= Self::FLAG_ROUTER;
437 }
438
439 if solicited_flag {
440 flags_rso |= Self::FLAG_SOLICITED;
441 }
442
443 if override_flag {
444 flags_rso |= Self::FLAG_OVERRIDE;
445 }
446
447 Self { flags_rso, _reserved: [0; 3], target_address }
448 }
449
450 pub fn target_address(&self) -> &Ipv6Addr {
452 &self.target_address
453 }
454
455 pub fn router_flag(&self) -> bool {
457 (self.flags_rso & Self::FLAG_ROUTER) != 0
458 }
459
460 pub fn solicited_flag(&self) -> bool {
462 (self.flags_rso & Self::FLAG_SOLICITED) != 0
463 }
464
465 pub fn override_flag(&self) -> bool {
467 (self.flags_rso & Self::FLAG_OVERRIDE) != 0
468 }
469}
470
471#[derive(
473 Copy, Clone, Debug, KnownLayout, FromBytes, IntoBytes, Immutable, Unaligned, PartialEq, Eq,
474)]
475#[repr(C)]
476pub struct Redirect {
477 _reserved: [u8; 4],
478 target_address: Ipv6Addr,
479 destination_address: Ipv6Addr,
480}
481
482impl_icmp_message!(Ipv6, Redirect, Redirect, IcmpZeroCode, Options<B>);
483
484pub mod options {
486 use core::num::NonZeroUsize;
487
488 use byteorder::{ByteOrder, NetworkEndian};
489 use net_types::UnicastAddress;
490 use net_types::ip::{IpAddress as _, Ipv6Addr, Subnet, SubnetError};
491 use packet::BufferView as _;
492 use packet::records::options::{
493 LengthEncoding, OptionBuilder, OptionLayout, OptionParseErr, OptionParseLayout, OptionsImpl,
494 };
495 use zerocopy::byteorder::network_endian::U32;
496 use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout, Ref, SplitByteSlice, Unaligned};
497
498 use super::NonZeroNdpLifetime;
499 use crate::utils::NonZeroDuration;
500
501 pub const INFINITE_LIFETIME_SECONDS: u32 = u32::MAX;
503
504 pub const INFINITE_LIFETIME: NonZeroDuration =
507 NonZeroDuration::from_secs(INFINITE_LIFETIME_SECONDS as u64).unwrap();
508
509 const REDIRECTED_HEADER_OPTION_RESERVED_BYTES_LENGTH: usize = 6;
516
517 const MTU_OPTION_LENGTH: usize = 6;
523
524 const MTU_OPTION_RESERVED_BYTES_LENGTH: usize = 2;
531
532 pub const MIN_NONCE_LENGTH: usize = 6;
538
539 const MIN_RECURSIVE_DNS_SERVER_OPTION_LENGTH: usize = 22;
549
550 const RECURSIVE_DNS_SERVER_OPTION_RESERVED_BYTES_LENGTH: usize = 2;
557
558 const ROUTE_INFORMATION_PREFERENCE_RESERVED_BITS_RIGHT: u8 = 3;
564
565 const ROUTE_INFORMATION_PREFERENCE_MASK: u8 = 0x18;
571
572 const OPTION_BYTES_PER_LENGTH_UNIT: usize = 8;
578
579 #[derive(Debug, PartialEq, Eq, Clone)]
585 pub struct RecursiveDnsServer<'a> {
586 lifetime: u32,
587 addresses: &'a [Ipv6Addr],
588 }
589
590 impl<'a> RecursiveDnsServer<'a> {
591 pub const INFINITE_LIFETIME: u32 = INFINITE_LIFETIME_SECONDS;
593
594 pub fn new(lifetime: u32, addresses: &'a [Ipv6Addr]) -> RecursiveDnsServer<'a> {
596 RecursiveDnsServer { lifetime, addresses }
597 }
598
599 pub fn lifetime(&self) -> Option<NonZeroNdpLifetime> {
605 NonZeroNdpLifetime::from_u32_with_infinite(self.lifetime)
606 }
607
608 pub fn iter_addresses(&self) -> &'a [Ipv6Addr] {
610 self.addresses
611 }
612
613 pub fn parse(data: &'a [u8]) -> Result<Self, OptionParseErr> {
616 if data.len() < MIN_RECURSIVE_DNS_SERVER_OPTION_LENGTH {
617 return Err(OptionParseErr);
618 }
619
620 let (_, data) = data.split_at(RECURSIVE_DNS_SERVER_OPTION_RESERVED_BYTES_LENGTH);
623
624 let (lifetime, data) = Ref::<_, U32>::from_prefix(data).map_err(|_| OptionParseErr)?;
627
628 let addresses = Ref::into_ref(
631 Ref::<_, [Ipv6Addr]>::from_bytes(data)
632 .map_err(Into::into)
633 .map_err(|_: zerocopy::SizeError<_, _>| OptionParseErr)?,
634 );
635
636 if !addresses.iter().all(UnicastAddress::is_unicast) {
638 return Err(OptionParseErr);
639 }
640
641 Ok(Self::new(lifetime.get(), addresses))
642 }
643 }
644
645 #[derive(KnownLayout, FromBytes, IntoBytes, Immutable, Unaligned)]
668 #[repr(C)]
669 struct RouteInformationHeader {
670 prefix_length: u8,
671 flags: u8,
672 route_lifetime: U32,
673 }
674
675 impl RouteInformationHeader {
676 const PREFERENCE_SHIFT: u8 = 3;
692 const PREFERENCE_MASK: u8 = 0b11 << Self::PREFERENCE_SHIFT;
693
694 fn set_preference(&mut self, preference: super::RoutePreference) {
695 let preference: u8 = preference.into();
696
697 self.flags &= !Self::PREFERENCE_MASK;
698 self.flags |= (preference << Self::PREFERENCE_SHIFT) & Self::PREFERENCE_MASK;
699 }
700 }
701
702 #[derive(Debug, PartialEq, Eq)]
708 pub struct RouteInformation {
709 prefix: Subnet<Ipv6Addr>,
710 route_lifetime_seconds: u32,
711 preference: super::RoutePreference,
712 }
713
714 impl RouteInformation {
715 pub fn new(
717 prefix: Subnet<Ipv6Addr>,
718 route_lifetime_seconds: u32,
719 preference: super::RoutePreference,
720 ) -> Self {
721 Self { prefix, route_lifetime_seconds, preference }
722 }
723
724 pub fn prefix(&self) -> &Subnet<Ipv6Addr> {
726 &self.prefix
727 }
728
729 pub fn preference(&self) -> super::RoutePreference {
731 self.preference
732 }
733
734 pub fn route_lifetime(&self) -> Option<NonZeroNdpLifetime> {
736 NonZeroNdpLifetime::from_u32_with_infinite(self.route_lifetime_seconds)
737 }
738
739 fn prefix_bytes_len(&self) -> usize {
740 let RouteInformation { prefix, route_lifetime_seconds: _, preference: _ } = self;
741
742 let prefix_length = prefix.prefix();
743 if prefix_length == 0 {
756 0
757 } else if prefix_length <= 64 {
758 core::mem::size_of::<Ipv6Addr>() / 2
759 } else {
760 core::mem::size_of::<Ipv6Addr>()
761 }
762 }
763
764 fn serialized_len(&self) -> usize {
765 core::mem::size_of::<RouteInformationHeader>() + self.prefix_bytes_len()
766 }
767
768 fn serialize(&self, buffer: &mut [u8]) {
769 let (mut hdr, buffer) = Ref::<_, RouteInformationHeader>::from_prefix(buffer)
770 .expect("expected buffer to hold enough bytes for serialization");
771
772 let prefix_bytes_len = self.prefix_bytes_len();
773 let RouteInformation { prefix, route_lifetime_seconds, preference } = self;
774
775 hdr.prefix_length = prefix.prefix();
776 hdr.set_preference(*preference);
777 hdr.route_lifetime.set(*route_lifetime_seconds);
778 buffer[..prefix_bytes_len]
779 .copy_from_slice(&prefix.network().bytes()[..prefix_bytes_len])
780 }
781 }
782
783 const PREFIX_INFORMATION_OPTION_LENGTH: usize = 30;
790
791 #[derive(
797 Debug, KnownLayout, FromBytes, IntoBytes, Immutable, Unaligned, PartialEq, Eq, Clone,
798 )]
799 #[repr(C)]
800 pub struct PrefixInformation {
801 prefix_length: u8,
802 flags_la: u8,
803 valid_lifetime: U32,
804 preferred_lifetime: U32,
805 _reserved: [u8; 4],
806 prefix: Ipv6Addr,
807 }
808
809 impl PrefixInformation {
810 const ON_LINK_FLAG: u8 = 0x80;
816
817 const AUTONOMOUS_ADDRESS_CONFIGURATION_FLAG: u8 = 0x40;
824
825 pub fn new(
827 prefix_length: u8,
828 on_link_flag: bool,
829 autonomous_address_configuration_flag: bool,
830 valid_lifetime: u32,
831 preferred_lifetime: u32,
832 prefix: Ipv6Addr,
833 ) -> Self {
834 let mut flags_la = 0;
835
836 if on_link_flag {
837 flags_la |= Self::ON_LINK_FLAG;
838 }
839
840 if autonomous_address_configuration_flag {
841 flags_la |= Self::AUTONOMOUS_ADDRESS_CONFIGURATION_FLAG;
842 }
843
844 Self {
845 prefix_length,
846 flags_la,
847 valid_lifetime: U32::new(valid_lifetime),
848 preferred_lifetime: U32::new(preferred_lifetime),
849 _reserved: [0; 4],
850 prefix,
851 }
852 }
853
854 pub fn prefix_length(&self) -> u8 {
856 self.prefix_length
857 }
858
859 pub fn on_link_flag(&self) -> bool {
866 (self.flags_la & Self::ON_LINK_FLAG) != 0
867 }
868
869 pub fn autonomous_address_configuration_flag(&self) -> bool {
871 (self.flags_la & Self::AUTONOMOUS_ADDRESS_CONFIGURATION_FLAG) != 0
872 }
873
874 pub fn valid_lifetime(&self) -> Option<NonZeroNdpLifetime> {
880 NonZeroNdpLifetime::from_u32_with_infinite(self.valid_lifetime.get())
881 }
882
883 pub fn preferred_lifetime(&self) -> Option<NonZeroNdpLifetime> {
889 NonZeroNdpLifetime::from_u32_with_infinite(self.preferred_lifetime.get())
890 }
891
892 pub fn prefix(&self) -> &Ipv6Addr {
899 &self.prefix
900 }
901
902 pub fn subnet(&self) -> Result<Subnet<Ipv6Addr>, SubnetError> {
904 Subnet::new(self.prefix, self.prefix_length)
905 }
906 }
907
908 pub mod option_types {
910 pub const PREFIX_INFORMATION: u8 = 3;
912
913 pub const RECURSIVE_DNS_SERVER: u8 = 25;
915
916 pub const DNS_SEARCH_LIST: u8 = 31;
918
919 pub const SIXLOWPAN_CONTEXT: u8 = 34;
921
922 pub const CAPTIVE_PORTAL: u8 = 37;
924
925 pub const PREF64: u8 = 38;
927
928 pub fn debug_name(option_type: u8) -> Option<&'static str> {
930 match option_type {
933 super::option_types::PREFIX_INFORMATION => Some("PREFIX_INFORMATION"),
934 super::option_types::RECURSIVE_DNS_SERVER => Some("RECURSIVE_DNS_SERVER"),
935 super::option_types::DNS_SEARCH_LIST => Some("DNS_SEARCH_LIST"),
936 super::option_types::SIXLOWPAN_CONTEXT => Some("SIXLOWPAN_CONTEXT"),
937 super::option_types::CAPTIVE_PORTAL => Some("CAPTIVE_PORTAL"),
938 super::option_types::PREF64 => Some("PREF64"),
939 _ => None,
940 }
941 }
942 }
943
944 use option_types::{PREFIX_INFORMATION, RECURSIVE_DNS_SERVER};
945
946 create_protocol_enum!(
947 #[allow(missing_docs)]
949 pub enum NdpOptionType: u8 {
950 SourceLinkLayerAddress, 1, "Source Link-Layer Address";
951 TargetLinkLayerAddress, 2, "Target Link-Layer Address";
952 PrefixInformation, PREFIX_INFORMATION, "Prefix Information";
953 RedirectedHeader, 4, "Redirected Header";
954 Mtu, 5, "MTU";
955 Nonce, 14, "Nonce";
956 RouteInformation, 24, "Route Information";
957 RecursiveDnsServer, RECURSIVE_DNS_SERVER, "Recursive DNS Server";
958 }
959 );
960
961 #[derive(Debug, PartialEq, Eq, Copy, Clone, PartialOrd, Ord)]
968 pub struct NdpNonce<B: SplitByteSlice> {
969 nonce: B,
970 }
971
972 impl<B: SplitByteSlice> NdpNonce<B> {
973 pub fn bytes(&self) -> &[u8] {
975 let Self { nonce } = self;
976 nonce.deref()
977 }
978
979 pub fn new(value: B) -> Result<Self, InvalidNonceError> {
982 let bytes = value.deref();
983 let nonce_option_length_bytes = bytes.len() + 2;
987 if nonce_option_length_bytes % 8 != 0 {
988 return Err(InvalidNonceError::ResultsInNonMultipleOf8);
989 }
990
991 let nonce_option_length_in_groups_of_8_bytes = nonce_option_length_bytes / 8;
992
993 match u8::try_from(nonce_option_length_in_groups_of_8_bytes) {
996 Ok(_) => (),
997 Err(_) => return Err(InvalidNonceError::TooLong),
998 };
999
1000 Ok(Self { nonce: value })
1001 }
1002 }
1003
1004 impl<B: SplitByteSlice> AsRef<[u8]> for NdpNonce<B> {
1005 fn as_ref(&self) -> &[u8] {
1006 self.bytes()
1007 }
1008 }
1009
1010 impl<'a> From<&'a [u8; MIN_NONCE_LENGTH]> for NdpNonce<&'a [u8]> {
1013 fn from(value: &'a [u8; MIN_NONCE_LENGTH]) -> Self {
1014 Self { nonce: &value[..] }
1015 }
1016 }
1017
1018 #[derive(Debug, PartialEq, Eq, Copy, Clone)]
1020 pub enum InvalidNonceError {
1021 ResultsInNonMultipleOf8,
1024 TooLong,
1026 }
1027
1028 #[allow(missing_docs)]
1030 #[derive(Debug, PartialEq, Eq)]
1031 pub enum NdpOption<'a> {
1032 SourceLinkLayerAddress(&'a [u8]),
1033 TargetLinkLayerAddress(&'a [u8]),
1034 PrefixInformation(&'a PrefixInformation),
1035
1036 RedirectedHeader { original_packet: &'a [u8] },
1037
1038 Mtu(u32),
1039 Nonce(NdpNonce<&'a [u8]>),
1040
1041 RecursiveDnsServer(RecursiveDnsServer<'a>),
1042 RouteInformation(RouteInformation),
1043 }
1044
1045 impl<'a> NdpOption<'a> {
1046 pub fn nonce(self) -> Option<NdpNonce<&'a [u8]>> {
1048 match self {
1049 NdpOption::Nonce(nonce) => Some(nonce),
1050 _ => None,
1051 }
1052 }
1053
1054 pub fn source_link_layer_address(self) -> Option<&'a [u8]> {
1056 match self {
1057 NdpOption::SourceLinkLayerAddress(a) => Some(a),
1058 _ => None,
1059 }
1060 }
1061
1062 pub fn target_link_layer_address(self) -> Option<&'a [u8]> {
1064 match self {
1065 NdpOption::TargetLinkLayerAddress(a) => Some(a),
1066 _ => None,
1067 }
1068 }
1069 }
1070
1071 #[derive(Debug)]
1073 pub struct NdpOptionsImpl;
1074
1075 impl<'a> OptionLayout for NdpOptionsImpl {
1076 type KindLenField = u8;
1077
1078 const LENGTH_ENCODING: LengthEncoding = LengthEncoding::TypeLengthValue {
1080 option_len_multiplier: NonZeroUsize::new(8).unwrap(),
1081 };
1082 }
1083
1084 impl OptionParseLayout for NdpOptionsImpl {
1085 type Error = OptionParseErr;
1087
1088 const END_OF_OPTIONS: Option<u8> = None;
1090 const NOP: Option<u8> = None;
1091 }
1092
1093 impl OptionsImpl for NdpOptionsImpl {
1094 type Option<'a> = NdpOption<'a>;
1095
1096 fn parse<'a>(
1097 kind: u8,
1098 mut data: &'a [u8],
1099 ) -> Result<Option<NdpOption<'a>>, OptionParseErr> {
1100 let kind = if let Ok(k) = NdpOptionType::try_from(kind) {
1101 k
1102 } else {
1103 return Ok(None);
1104 };
1105
1106 let opt = match kind {
1107 NdpOptionType::SourceLinkLayerAddress => NdpOption::SourceLinkLayerAddress(data),
1108 NdpOptionType::TargetLinkLayerAddress => NdpOption::TargetLinkLayerAddress(data),
1109 NdpOptionType::PrefixInformation => {
1110 let data = Ref::<_, PrefixInformation>::from_bytes(data)
1111 .map_err(|_| OptionParseErr)?;
1112 NdpOption::PrefixInformation(Ref::into_ref(data))
1113 }
1114 NdpOptionType::RedirectedHeader => NdpOption::RedirectedHeader {
1115 original_packet: &data[REDIRECTED_HEADER_OPTION_RESERVED_BYTES_LENGTH..],
1116 },
1117 NdpOptionType::Mtu => NdpOption::Mtu(NetworkEndian::read_u32(
1118 &data[MTU_OPTION_RESERVED_BYTES_LENGTH..],
1119 )),
1120 NdpOptionType::Nonce => NdpOption::Nonce(
1121 NdpNonce::new(data).map_err(|_: InvalidNonceError| OptionParseErr)?,
1122 ),
1123 NdpOptionType::RecursiveDnsServer => {
1124 NdpOption::RecursiveDnsServer(RecursiveDnsServer::parse(data)?)
1125 }
1126 NdpOptionType::RouteInformation => {
1127 #[derive(KnownLayout, FromBytes, Immutable, Unaligned)]
1130 #[repr(C)]
1131 struct RouteInfoFixed {
1132 prefix_length: u8,
1133 preference_raw: u8,
1134 route_lifetime_seconds: U32,
1135 }
1136
1137 let mut buf = &mut data;
1138
1139 let fixed = buf.take_obj_front::<RouteInfoFixed>().ok_or(OptionParseErr)?;
1140
1141 let preference = super::RoutePreference::try_from(
1143 (fixed.preference_raw & ROUTE_INFORMATION_PREFERENCE_MASK)
1144 >> ROUTE_INFORMATION_PREFERENCE_RESERVED_BITS_RIGHT,
1145 )
1146 .map_err(|()| OptionParseErr)?;
1147
1148 let buf_len = buf.len();
1160 if buf_len % OPTION_BYTES_PER_LENGTH_UNIT != 0 {
1161 return Err(OptionParseErr);
1162 }
1163 let length = buf_len / OPTION_BYTES_PER_LENGTH_UNIT;
1164 match (fixed.prefix_length, length) {
1165 (65..=128, 2) => {}
1166 (1..=64, 1 | 2) => {}
1167 (0, 0 | 1 | 2) => {}
1168 _ => return Err(OptionParseErr),
1169 }
1170
1171 let mut prefix_buf = [0; 16];
1172 prefix_buf[..buf_len].copy_from_slice(&buf);
1174 let prefix = Ipv6Addr::from_bytes(prefix_buf);
1175
1176 NdpOption::RouteInformation(RouteInformation::new(
1177 Subnet::new(prefix, fixed.prefix_length).map_err(|_| OptionParseErr)?,
1178 fixed.route_lifetime_seconds.get(),
1179 preference,
1180 ))
1181 }
1182 };
1183
1184 Ok(Some(opt))
1185 }
1186 }
1187
1188 #[allow(missing_docs)]
1190 #[derive(Debug)]
1191 pub enum NdpOptionBuilder<'a> {
1192 SourceLinkLayerAddress(&'a [u8]),
1193 TargetLinkLayerAddress(&'a [u8]),
1194 PrefixInformation(PrefixInformation),
1195
1196 RedirectedHeader { original_packet: &'a [u8] },
1197
1198 Mtu(u32),
1199 Nonce(NdpNonce<&'a [u8]>),
1200
1201 RouteInformation(RouteInformation),
1202 RecursiveDnsServer(RecursiveDnsServer<'a>),
1203 }
1204
1205 impl<'a> From<&NdpOptionBuilder<'a>> for NdpOptionType {
1206 fn from(v: &NdpOptionBuilder<'a>) -> Self {
1207 match v {
1208 NdpOptionBuilder::SourceLinkLayerAddress(_) => {
1209 NdpOptionType::SourceLinkLayerAddress
1210 }
1211 NdpOptionBuilder::TargetLinkLayerAddress(_) => {
1212 NdpOptionType::TargetLinkLayerAddress
1213 }
1214 NdpOptionBuilder::PrefixInformation(_) => NdpOptionType::PrefixInformation,
1215 NdpOptionBuilder::RedirectedHeader { .. } => NdpOptionType::RedirectedHeader,
1216 NdpOptionBuilder::Mtu { .. } => NdpOptionType::Mtu,
1217 NdpOptionBuilder::Nonce(_) => NdpOptionType::Nonce,
1218 NdpOptionBuilder::RouteInformation(_) => NdpOptionType::RouteInformation,
1219 NdpOptionBuilder::RecursiveDnsServer(_) => NdpOptionType::RecursiveDnsServer,
1220 }
1221 }
1222 }
1223
1224 impl<'a> OptionBuilder for NdpOptionBuilder<'a> {
1225 type Layout = NdpOptionsImpl;
1226
1227 fn serialized_len(&self) -> usize {
1228 match self {
1229 NdpOptionBuilder::SourceLinkLayerAddress(data)
1230 | NdpOptionBuilder::TargetLinkLayerAddress(data) => data.len(),
1231 NdpOptionBuilder::PrefixInformation(_) => PREFIX_INFORMATION_OPTION_LENGTH,
1232 NdpOptionBuilder::RedirectedHeader { original_packet } => {
1233 REDIRECTED_HEADER_OPTION_RESERVED_BYTES_LENGTH + original_packet.len()
1234 }
1235 NdpOptionBuilder::Mtu(_) => MTU_OPTION_LENGTH,
1236 NdpOptionBuilder::Nonce(NdpNonce { nonce }) => nonce.len(),
1237 NdpOptionBuilder::RouteInformation(o) => o.serialized_len(),
1238 NdpOptionBuilder::RecursiveDnsServer(RecursiveDnsServer {
1239 lifetime,
1240 addresses,
1241 }) => {
1242 RECURSIVE_DNS_SERVER_OPTION_RESERVED_BYTES_LENGTH
1243 + core::mem::size_of_val(lifetime)
1244 + core::mem::size_of_val(*addresses)
1245 }
1246 }
1247 }
1248
1249 fn option_kind(&self) -> u8 {
1250 NdpOptionType::from(self).into()
1251 }
1252
1253 fn serialize_into(&self, buffer: &mut [u8]) {
1254 match self {
1255 NdpOptionBuilder::SourceLinkLayerAddress(data)
1256 | NdpOptionBuilder::TargetLinkLayerAddress(data) => buffer.copy_from_slice(data),
1257 NdpOptionBuilder::PrefixInformation(pfx_info) => {
1258 buffer.copy_from_slice(pfx_info.as_bytes());
1259 }
1260 NdpOptionBuilder::RedirectedHeader { original_packet } => {
1261 let (reserved_bytes, original_packet_bytes) =
1265 buffer.split_at_mut(REDIRECTED_HEADER_OPTION_RESERVED_BYTES_LENGTH);
1266 reserved_bytes
1267 .copy_from_slice(&[0; REDIRECTED_HEADER_OPTION_RESERVED_BYTES_LENGTH]);
1268 original_packet_bytes.copy_from_slice(original_packet);
1269 }
1270 NdpOptionBuilder::Mtu(mtu) => {
1271 let (reserved_bytes, mtu_bytes) =
1274 buffer.split_at_mut(MTU_OPTION_RESERVED_BYTES_LENGTH);
1275 reserved_bytes.copy_from_slice(&[0; MTU_OPTION_RESERVED_BYTES_LENGTH]);
1276 mtu_bytes.copy_from_slice(U32::new(*mtu).as_bytes());
1277 }
1278 NdpOptionBuilder::Nonce(NdpNonce { nonce }) => {
1279 buffer.copy_from_slice(nonce);
1280 }
1281 NdpOptionBuilder::RouteInformation(p) => p.serialize(buffer),
1282 NdpOptionBuilder::RecursiveDnsServer(RecursiveDnsServer {
1283 lifetime,
1284 addresses,
1285 }) => {
1286 let (reserved_bytes, buffer) =
1289 buffer.split_at_mut(RECURSIVE_DNS_SERVER_OPTION_RESERVED_BYTES_LENGTH);
1290 reserved_bytes
1291 .copy_from_slice(&[0; RECURSIVE_DNS_SERVER_OPTION_RESERVED_BYTES_LENGTH]);
1292
1293 let (lifetime_bytes, addresses_bytes) =
1297 buffer.split_at_mut(core::mem::size_of_val(lifetime));
1298 lifetime_bytes.copy_from_slice(U32::new(*lifetime).as_bytes());
1299 addresses_bytes.copy_from_slice(addresses.as_bytes());
1300 }
1301 }
1302 }
1303 }
1304}
1305
1306#[cfg(test)]
1307mod tests {
1308 use byteorder::{ByteOrder, NetworkEndian};
1309 use net_types::ip::{Ip, IpAddress, Subnet};
1310 use packet::{
1311 EmptyBuf, InnerPacketBuilder, NestablePacketBuilder as _, NestableSerializer as _,
1312 NoOpSerializationContext, ParseBuffer, Serializer,
1313 };
1314 use test_case::test_case;
1315 use zerocopy::Ref;
1316
1317 use super::*;
1318 use crate::icmp::{IcmpPacketBuilder, IcmpParseArgs};
1319 use crate::ipv6::{Ipv6Header, Ipv6Packet};
1320
1321 #[test]
1322 fn parse_serialize_redirected_header() {
1323 let expected_packet = [1, 2, 3, 4, 5, 6, 7, 8];
1324 let options =
1325 &[options::NdpOptionBuilder::RedirectedHeader { original_packet: &expected_packet }];
1326 let serialized = OptionSequenceBuilder::new(options.iter())
1327 .into_serializer()
1328 .serialize_vec_outer(&mut NoOpSerializationContext)
1329 .unwrap();
1330 let mut expected = [0; 16];
1332 (&mut expected[..2]).copy_from_slice(&[4, 2]);
1337 (&mut expected[8..]).copy_from_slice(&expected_packet);
1338 assert_eq!(serialized.as_ref(), expected);
1339
1340 let parsed = Options::parse(&expected[..]).unwrap();
1341 let parsed = parsed.iter().collect::<Vec<options::NdpOption<'_>>>();
1342 assert_eq!(parsed.len(), 1);
1343 assert_eq!(
1344 options::NdpOption::RedirectedHeader { original_packet: &expected_packet },
1345 parsed[0]
1346 );
1347 }
1348
1349 #[test]
1350 fn parse_serialize_mtu_option() {
1351 let expected_mtu = 5781;
1352 let options = &[options::NdpOptionBuilder::Mtu(expected_mtu)];
1353 let serialized = OptionSequenceBuilder::new(options.iter())
1354 .into_serializer()
1355 .serialize_vec_outer(&mut NoOpSerializationContext)
1356 .unwrap();
1357 let mut expected = [5, 1, 0, 0, 0, 0, 0, 0];
1362 NetworkEndian::write_u32(&mut expected[4..], expected_mtu);
1363 assert_eq!(serialized.as_ref(), expected);
1364
1365 let parsed = Options::parse(&expected[..]).unwrap();
1366 let parsed = parsed.iter().collect::<Vec<options::NdpOption<'_>>>();
1367 assert_eq!(parsed.len(), 1);
1368 assert_eq!(options::NdpOption::Mtu(expected_mtu), parsed[0]);
1369 }
1370
1371 #[test_case(
1372 options::MIN_NONCE_LENGTH - 1 =>
1373 matches Err(options::InvalidNonceError::ResultsInNonMultipleOf8);
1374 "resulting nonce option length must be multiple of 8")]
1375 #[test_case(
1376 options::MIN_NONCE_LENGTH => matches Ok(_);
1377 "MIN_NONCE_LENGTH must validate successfully")]
1378 #[test_case(
1379 usize::from(u8::MAX) * 8 - 2 => matches Ok(_);
1380 "maximum possible nonce length must validate successfully")]
1381 #[test_case(
1382 usize::from(u8::MAX) * 8 - 2 + 8 =>
1383 matches Err(options::InvalidNonceError::TooLong);
1384 "nonce option's length must fit in u8")]
1385 fn nonce_length_validation(
1386 length: usize,
1387 ) -> Result<options::NdpNonce<&'static [u8]>, options::InvalidNonceError> {
1388 const LEN: usize = (u8::MAX as usize + 1) * 8;
1389 const BYTES: [u8; LEN] = [0u8; LEN];
1390 options::NdpNonce::new(&BYTES[..length])
1391 }
1392
1393 #[test]
1394 fn parse_serialize_nonce_option() {
1395 let expected_nonce: [u8; 6] = [1, 2, 3, 4, 5, 6];
1396 let nonce = options::NdpNonce::new(&expected_nonce[..]).expect("should be valid nonce");
1397 let options = &[options::NdpOptionBuilder::Nonce(nonce)];
1398 let serialized = OptionSequenceBuilder::new(options.iter())
1399 .into_serializer()
1400 .serialize_vec_outer(&mut NoOpSerializationContext)
1401 .unwrap();
1402
1403 let mut expected_bytes: [u8; 8] = [14, 1, 0, 0, 0, 0, 0, 0];
1406 expected_bytes[2..].copy_from_slice(&expected_nonce);
1407
1408 assert_eq!(serialized.as_ref(), expected_bytes);
1409
1410 let parsed = Options::parse(&expected_bytes[..]).unwrap();
1411 let parsed = parsed.iter().collect::<Vec<options::NdpOption<'_>>>();
1412 assert_eq!(parsed.len(), 1);
1413 assert_eq!(parsed[0], options::NdpOption::Nonce(nonce));
1414 }
1415
1416 #[test]
1417 fn parse_serialize_prefix_option() {
1418 let expected_prefix_info = options::PrefixInformation::new(
1419 120,
1420 true,
1421 false,
1422 100,
1423 100,
1424 Ipv6Addr::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 168, 0, 0]),
1425 );
1426 let options = &[options::NdpOptionBuilder::PrefixInformation(expected_prefix_info.clone())];
1427 let serialized = OptionSequenceBuilder::new(options.iter())
1428 .into_serializer()
1429 .serialize_vec_outer(&mut NoOpSerializationContext)
1430 .unwrap();
1431 let mut expected = [0; 32];
1436 expected[0] = 3;
1437 expected[1] = 4;
1438 (&mut expected[2..]).copy_from_slice(expected_prefix_info.as_bytes());
1439 assert_eq!(serialized.as_ref(), expected);
1440
1441 let parsed = Options::parse(&expected[..]).unwrap();
1442 let parsed = parsed.iter().collect::<Vec<options::NdpOption<'_>>>();
1443 assert_eq!(parsed.len(), 1);
1444 assert_eq!(options::NdpOption::PrefixInformation(&expected_prefix_info), parsed[0]);
1445 }
1446
1447 #[test]
1448 fn parse_serialize_rdnss_option() {
1449 let test = |addrs: &[Ipv6Addr]| {
1450 let lifetime = 120;
1451 let expected_rdnss = options::RecursiveDnsServer::new(lifetime, addrs);
1452 let options = &[options::NdpOptionBuilder::RecursiveDnsServer(expected_rdnss.clone())];
1453 let serialized = OptionSequenceBuilder::new(options.iter())
1454 .into_serializer()
1455 .serialize_vec_outer(&mut NoOpSerializationContext)
1456 .unwrap();
1457 let mut expected = vec![0; 8 + addrs.len() * usize::from(Ipv6Addr::BYTES)];
1460 (&mut expected[..4]).copy_from_slice(&[
1465 25,
1466 1 + u8::try_from(addrs.len()).unwrap() * 2,
1467 0,
1468 0,
1469 ]);
1470 NetworkEndian::write_u32(&mut expected[4..8], lifetime);
1472 (&mut expected[8..]).copy_from_slice(addrs.as_bytes());
1474 assert_eq!(serialized.as_ref(), expected.as_slice());
1475
1476 let parsed = Options::parse(&expected[..])
1477 .expect("should have parsed a valid recursive dns erver option");
1478 let parsed = parsed.iter().collect::<Vec<options::NdpOption<'_>>>();
1479 assert_eq!(parsed.len(), 1);
1480
1481 assert_eq!(
1483 options::RecursiveDnsServer::parse(&expected[2..]).expect("parsing should succeed"),
1484 expected_rdnss
1485 );
1486
1487 assert_eq!(options::NdpOption::RecursiveDnsServer(expected_rdnss), parsed[0]);
1488 };
1489 test(&[Ipv6Addr::from([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16])]);
1490 test(&[
1491 Ipv6Addr::from([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]),
1492 Ipv6Addr::from([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17]),
1493 ]);
1494 }
1495
1496 #[test]
1497 fn parse_serialize_rdnss_option_error() {
1498 let addrs = [
1499 Ipv6Addr::from([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]),
1500 Ipv6Addr::from([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17]),
1501 ];
1502 let lifetime = 120;
1503 let mut buf = vec![0; 8 + addrs.len() * usize::from(Ipv6Addr::BYTES)];
1506 (&mut buf[..4]).copy_from_slice(&[25, 1 + u8::try_from(addrs.len()).unwrap() * 2, 0, 0]);
1511 NetworkEndian::write_u32(&mut buf[4..8], lifetime);
1513 (&mut buf[8..]).copy_from_slice(addrs.as_bytes());
1515
1516 let _parsed = Options::parse(&buf[..])
1518 .expect("should have parsed a valid recursive dns erver option");
1519
1520 let _err = Options::parse(&buf[..8]).expect_err(
1522 "should not have parsed a recursive dns server option that has no addresses",
1523 );
1524
1525 let _err = Options::parse(&buf[..buf.len()-1])
1527 .expect_err("should not have parsed a recursive dns server option that cuts off in the middle of an address");
1528
1529 (&mut buf[8..8 + usize::from(Ipv6Addr::BYTES)])
1531 .copy_from_slice(Ipv6::UNSPECIFIED_ADDRESS.as_bytes());
1532 let _parsed = Options::parse(&buf[..]).expect_err(
1533 "should not have parsed a recursive dns erver option with an unspecified address",
1534 );
1535
1536 (&mut buf[8..8 + usize::from(Ipv6Addr::BYTES)])
1538 .copy_from_slice(Ipv6::ALL_NODES_LINK_LOCAL_MULTICAST_ADDRESS.as_bytes());
1539 let _parsed = Options::parse(&buf[..]).expect_err(
1540 "should not have parsed a recursive dns erver option with a multicast address",
1541 );
1542 }
1543
1544 #[test]
1545 fn parse_neighbor_solicitation() {
1546 use crate::icmp::testdata::ndp_neighbor::*;
1547 let mut buf = SOLICITATION_IP_PACKET_BYTES;
1548 let ip = buf.parse::<Ipv6Packet<_>>().unwrap();
1549 let ipv6_builder = ip.builder();
1550 let (src_ip, dst_ip) = (ip.src_ip(), ip.dst_ip());
1551 let icmp = buf
1552 .parse_with::<_, IcmpPacket<_, _, NeighborSolicitation>>(IcmpParseArgs::new(
1553 src_ip, dst_ip,
1554 ))
1555 .unwrap();
1556
1557 assert_eq!(icmp.message().target_address.ipv6_bytes(), TARGET_ADDRESS);
1558 let collected = icmp.ndp_options().iter().collect::<Vec<options::NdpOption<'_>>>();
1559 for option in collected.iter() {
1560 match option {
1561 options::NdpOption::SourceLinkLayerAddress(address) => {
1562 assert_eq!(address, &SOURCE_LINK_LAYER_ADDRESS);
1563 }
1564 o => panic!("Found unexpected option: {:?}", o),
1565 }
1566 }
1567 let option_builders =
1568 [options::NdpOptionBuilder::SourceLinkLayerAddress(&SOURCE_LINK_LAYER_ADDRESS)];
1569 let serialized = OptionSequenceBuilder::new(option_builders.iter())
1570 .into_serializer()
1571 .wrap_in(IcmpPacketBuilder::<Ipv6, _>::new(
1572 src_ip,
1573 dst_ip,
1574 IcmpZeroCode,
1575 *icmp.message(),
1576 ))
1577 .wrap_in(ipv6_builder)
1578 .serialize_vec_outer(&mut NoOpSerializationContext)
1579 .unwrap()
1580 .as_ref()
1581 .to_vec();
1582 assert_eq!(&serialized, &SOLICITATION_IP_PACKET_BYTES)
1583 }
1584
1585 #[test]
1586 fn parse_neighbor_advertisement() {
1587 use crate::icmp::testdata::ndp_neighbor::*;
1588 let mut buf = ADVERTISEMENT_IP_PACKET_BYTES;
1589 let ip = buf.parse::<Ipv6Packet<_>>().unwrap();
1590 let ipv6_builder = ip.builder();
1591 let (src_ip, dst_ip) = (ip.src_ip(), ip.dst_ip());
1592 let icmp = buf
1593 .parse_with::<_, IcmpPacket<_, _, NeighborAdvertisement>>(IcmpParseArgs::new(
1594 src_ip, dst_ip,
1595 ))
1596 .unwrap();
1597 assert_eq!(icmp.message().target_address.ipv6_bytes(), TARGET_ADDRESS);
1598 assert_eq!(icmp.ndp_options().iter().count(), 0);
1599
1600 let serialized = EmptyBuf
1601 .wrap_in(IcmpPacketBuilder::<Ipv6, _>::new(
1602 src_ip,
1603 dst_ip,
1604 IcmpZeroCode,
1605 *icmp.message(),
1606 ))
1607 .wrap_in(ipv6_builder)
1608 .serialize_vec_outer(&mut NoOpSerializationContext)
1609 .unwrap()
1610 .as_ref()
1611 .to_vec();
1612 assert_eq!(&serialized, &ADVERTISEMENT_IP_PACKET_BYTES);
1613 }
1614
1615 #[test]
1616 fn parse_router_advertisement() {
1617 use crate::icmp::ndp::options::RouteInformation;
1618 use crate::icmp::testdata::ndp_router::*;
1619
1620 let mut buf = ADVERTISEMENT_IP_PACKET_BYTES;
1621 let ip = buf.parse::<Ipv6Packet<_>>().unwrap();
1622 let ipv6_builder = ip.builder();
1623 let (src_ip, dst_ip) = (ip.src_ip(), ip.dst_ip());
1624 let icmp = buf
1625 .parse_with::<_, IcmpPacket<_, _, RouterAdvertisement>>(IcmpParseArgs::new(
1626 src_ip, dst_ip,
1627 ))
1628 .unwrap();
1629 assert_eq!(icmp.message().current_hop_limit(), HOP_LIMIT);
1630 assert_eq!(icmp.message().router_lifetime(), LIFETIME);
1631 assert_eq!(icmp.message().reachable_time(), REACHABLE_TIME);
1632 assert_eq!(icmp.message().retransmit_timer(), RETRANS_TIMER);
1633
1634 assert_eq!(icmp.ndp_options().iter().count(), 5);
1635
1636 let collected = icmp.ndp_options().iter().collect::<Vec<options::NdpOption<'_>>>();
1637 for option in collected.iter() {
1638 match option {
1639 options::NdpOption::SourceLinkLayerAddress(address) => {
1640 assert_eq!(address, &SOURCE_LINK_LAYER_ADDRESS);
1641 }
1642 options::NdpOption::PrefixInformation(info) => {
1643 assert_eq!(info.on_link_flag(), PREFIX_INFO_ON_LINK_FLAG);
1644 assert_eq!(
1645 info.autonomous_address_configuration_flag(),
1646 PREFIX_INFO_AUTONOMOUS_ADDRESS_CONFIGURATION_FLAG
1647 );
1648 assert_eq!(
1649 info.valid_lifetime(),
1650 NonZeroNdpLifetime::from_u32_with_infinite(
1651 PREFIX_INFO_VALID_LIFETIME_SECONDS
1652 )
1653 );
1654 assert_eq!(
1655 info.preferred_lifetime(),
1656 NonZeroNdpLifetime::from_u32_with_infinite(
1657 PREFIX_INFO_PREFERRED_LIFETIME_SECONDS
1658 )
1659 );
1660 assert_eq!(info.prefix_length(), PREFIX_INFO_PREFIX.prefix());
1661 assert_eq!(info.prefix(), &PREFIX_INFO_PREFIX.network());
1662 }
1663 options::NdpOption::RouteInformation(_) => {
1664 }
1666 o => panic!("Found unexpected option: {:?}", o),
1667 }
1668 }
1669
1670 let mut route_information_options = collected
1671 .iter()
1672 .filter_map(|o| match o {
1673 options::NdpOption::RouteInformation(info) => Some(info),
1674 _ => None,
1675 })
1676 .collect::<Vec<&RouteInformation>>();
1677 route_information_options.sort_by_key(|o| o.prefix().prefix());
1682 assert_eq!(
1683 route_information_options,
1684 [
1685 &options::RouteInformation::new(
1686 ROUTE_INFO_LOW_PREF_PREFIX,
1687 ROUTE_INFO_LOW_PREF_VALID_LIFETIME_SECONDS,
1688 ROUTE_INFO_LOW_PREF,
1689 ),
1690 &options::RouteInformation::new(
1691 ROUTE_INFO_MEDIUM_PREF_PREFIX,
1692 ROUTE_INFO_MEDIUM_PREF_VALID_LIFETIME_SECONDS,
1693 ROUTE_INFO_MEDIUM_PREF,
1694 ),
1695 &options::RouteInformation::new(
1696 ROUTE_INFO_HIGH_PREF_PREFIX,
1697 ROUTE_INFO_HIGH_PREF_VALID_LIFETIME_SECONDS,
1698 ROUTE_INFO_HIGH_PREF,
1699 )
1700 ]
1701 );
1702
1703 let option_builders = [
1704 options::NdpOptionBuilder::SourceLinkLayerAddress(&SOURCE_LINK_LAYER_ADDRESS),
1705 options::NdpOptionBuilder::PrefixInformation(options::PrefixInformation::new(
1706 PREFIX_INFO_PREFIX.prefix(),
1707 PREFIX_INFO_ON_LINK_FLAG,
1708 PREFIX_INFO_AUTONOMOUS_ADDRESS_CONFIGURATION_FLAG,
1709 PREFIX_INFO_VALID_LIFETIME_SECONDS,
1710 PREFIX_INFO_PREFERRED_LIFETIME_SECONDS,
1711 PREFIX_INFO_PREFIX.network(),
1712 )),
1713 options::NdpOptionBuilder::RouteInformation(options::RouteInformation::new(
1714 ROUTE_INFO_HIGH_PREF_PREFIX,
1715 ROUTE_INFO_HIGH_PREF_VALID_LIFETIME_SECONDS,
1716 ROUTE_INFO_HIGH_PREF,
1717 )),
1718 options::NdpOptionBuilder::RouteInformation(options::RouteInformation::new(
1719 ROUTE_INFO_MEDIUM_PREF_PREFIX,
1720 ROUTE_INFO_MEDIUM_PREF_VALID_LIFETIME_SECONDS,
1721 ROUTE_INFO_MEDIUM_PREF,
1722 )),
1723 options::NdpOptionBuilder::RouteInformation(options::RouteInformation::new(
1724 ROUTE_INFO_LOW_PREF_PREFIX,
1725 ROUTE_INFO_LOW_PREF_VALID_LIFETIME_SECONDS,
1726 ROUTE_INFO_LOW_PREF,
1727 )),
1728 ];
1729 let serialized = OptionSequenceBuilder::new(option_builders.iter())
1730 .into_serializer()
1731 .wrap_in(IcmpPacketBuilder::<Ipv6, _>::new(
1732 src_ip,
1733 dst_ip,
1734 IcmpZeroCode,
1735 *icmp.message(),
1736 ))
1737 .wrap_in(ipv6_builder)
1738 .serialize_vec_outer(&mut NoOpSerializationContext)
1739 .unwrap()
1740 .as_ref()
1741 .to_vec();
1742 assert_eq!(&serialized, &ADVERTISEMENT_IP_PACKET_BYTES);
1743 }
1744
1745 struct SerializeRATest {
1746 hop_limit: u8,
1747 managed_flag: bool,
1748 other_config_flag: bool,
1749 preference: RoutePreference,
1750 router_lifetime_seconds: u16,
1751 reachable_time_seconds: u32,
1752 retransmit_timer_seconds: u32,
1753 }
1754
1755 #[test_case(
1756 SerializeRATest{
1757 hop_limit: 1,
1758 managed_flag: true,
1759 other_config_flag: false,
1760 preference: RoutePreference::High,
1761 router_lifetime_seconds: 1_000,
1762 reachable_time_seconds: 1_000_000,
1763 retransmit_timer_seconds: 5,
1764 }; "test_1")]
1765 #[test_case(
1766 SerializeRATest{
1767 hop_limit: 64,
1768 managed_flag: false,
1769 other_config_flag: true,
1770 preference: RoutePreference::Low,
1771 router_lifetime_seconds: 5,
1772 reachable_time_seconds: 23425621,
1773 retransmit_timer_seconds: 13252521,
1774 }; "test_2")]
1775 fn serialize_router_advertisement(test: SerializeRATest) {
1776 let SerializeRATest {
1777 hop_limit,
1778 managed_flag,
1779 other_config_flag,
1780 preference,
1781 router_lifetime_seconds,
1782 reachable_time_seconds,
1783 retransmit_timer_seconds,
1784 } = test;
1785
1786 const SRC_IP: Ipv6Addr =
1787 Ipv6Addr::from_bytes([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
1788 const DST_IP: Ipv6Addr =
1789 Ipv6Addr::from_bytes([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17]);
1790 let icmp = IcmpPacketBuilder::<Ipv6, _>::new(
1791 SRC_IP,
1792 DST_IP,
1793 IcmpZeroCode,
1794 RouterAdvertisement::with_prf(
1795 hop_limit,
1796 managed_flag,
1797 other_config_flag,
1798 preference,
1799 router_lifetime_seconds,
1800 reachable_time_seconds,
1801 retransmit_timer_seconds,
1802 ),
1803 );
1804 let serialized =
1805 icmp.wrap_body(EmptyBuf).serialize_vec_outer(&mut NoOpSerializationContext).unwrap();
1806
1807 const RA_LEN: u32 = 16;
1829 let mut expected = [0; RA_LEN as usize];
1830 expected[0] = 134;
1831 expected[4] = hop_limit;
1832 if managed_flag {
1833 expected[5] |= 1 << 7;
1834 }
1835 if other_config_flag {
1836 expected[5] |= 1 << 6;
1837 }
1838 expected[5] |= u8::from(preference) << 3;
1839 let (mut router_lifetime, _rest) = Ref::<_, U16>::from_prefix(&mut expected[6..]).unwrap();
1840 router_lifetime.set(router_lifetime_seconds);
1841 let (mut reachable_time, _rest) = Ref::<_, U32>::from_prefix(&mut expected[8..]).unwrap();
1842 reachable_time.set(reachable_time_seconds);
1843 let (mut retransmit_timer, _rest) =
1844 Ref::<_, U32>::from_prefix(&mut expected[12..]).unwrap();
1845 retransmit_timer.set(retransmit_timer_seconds);
1846
1847 let mut c = internet_checksum::Checksum::new();
1848 c.add_bytes(SRC_IP.bytes());
1850 c.add_bytes(DST_IP.bytes());
1851 c.add_bytes(U32::new(RA_LEN).as_bytes());
1852 c.add_bytes(&[0, crate::ip::Ipv6Proto::Icmpv6.into()]);
1853 c.add_bytes(&expected[..]);
1855 expected[2..4].copy_from_slice(&c.checksum()[..]);
1856
1857 assert_eq!(serialized.as_ref(), &expected[..]);
1858 }
1859
1860 struct SerializeRioTest {
1861 prefix_length: u8,
1862 route_lifetime_seconds: u32,
1863 preference: RoutePreference,
1864 expected_option_length: u8,
1865 }
1866
1867 #[test_case(
1877 SerializeRioTest{
1878 prefix_length: 0,
1879 route_lifetime_seconds: 1,
1880 preference: RoutePreference::High,
1881 expected_option_length: 8,
1882 }; "prefix_length_0")]
1883 #[test_case(
1884 SerializeRioTest{
1885 prefix_length: 1,
1886 route_lifetime_seconds: 1000,
1887 preference: RoutePreference::Medium,
1888 expected_option_length: 16,
1889 }; "prefix_length_1")]
1890 #[test_case(
1891 SerializeRioTest{
1892 prefix_length: 64,
1893 route_lifetime_seconds: 100000,
1894 preference: RoutePreference::Low,
1895 expected_option_length: 16,
1896 }; "prefix_length_64")]
1897 #[test_case(
1898 SerializeRioTest{
1899 prefix_length: 65,
1900 route_lifetime_seconds: 1000000,
1901 preference: RoutePreference::Medium,
1902 expected_option_length: 24,
1903 }; "prefix_length_65")]
1904 #[test_case(
1905 SerializeRioTest{
1906 prefix_length: 128,
1907 route_lifetime_seconds: 10000000,
1908 preference: RoutePreference::Medium,
1909 expected_option_length: 24,
1910 }; "prefix_length_128")]
1911 fn serialize_route_information_option(test: SerializeRioTest) {
1912 const IPV6ADDR: Ipv6Addr =
1913 Ipv6Addr::new([0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff]);
1914
1915 let SerializeRioTest {
1916 prefix_length,
1917 route_lifetime_seconds,
1918 preference,
1919 expected_option_length,
1920 } = test;
1921 let prefix = IPV6ADDR.mask(prefix_length);
1922
1923 let option_builders =
1924 [options::NdpOptionBuilder::RouteInformation(options::RouteInformation::new(
1925 Subnet::new(prefix, prefix_length).unwrap(),
1926 route_lifetime_seconds,
1927 preference,
1928 ))];
1929
1930 let serialized = OptionSequenceBuilder::new(option_builders.iter())
1931 .into_serializer()
1932 .serialize_vec_outer(&mut NoOpSerializationContext)
1933 .unwrap();
1934
1935 let mut expected = [0; 24];
1963 expected[0] = 24;
1964 expected[1] = expected_option_length / 8;
1965 expected[2] = prefix_length;
1966 expected[3] = u8::from(preference) << 3;
1967 let (mut lifetime_seconds, _rest) = Ref::<_, U32>::from_prefix(&mut expected[4..]).unwrap();
1968 lifetime_seconds.set(route_lifetime_seconds);
1969 expected[8..].copy_from_slice(prefix.bytes());
1970
1971 assert_eq!(serialized.as_ref(), &expected[..expected_option_length.into()]);
1972 }
1973
1974 #[test_case(0, None)]
1975 #[test_case(
1976 1,
1977 Some(NonZeroNdpLifetime::Finite(NonZeroDuration::new(
1978 Duration::from_secs(1),
1979 ).unwrap()))
1980 )]
1981 #[test_case(
1982 u32::MAX - 1,
1983 Some(NonZeroNdpLifetime::Finite(NonZeroDuration::new(
1984 Duration::from_secs(u64::from(u32::MAX) - 1),
1985 ).unwrap()))
1986 )]
1987 #[test_case(u32::MAX, Some(NonZeroNdpLifetime::Infinite))]
1988 fn non_zero_ndp_lifetime_non_zero_or_max_u32_from_u32_with_infinite(
1989 t: u32,
1990 expected: Option<NonZeroNdpLifetime>,
1991 ) {
1992 assert_eq!(NonZeroNdpLifetime::from_u32_with_infinite(t), expected)
1993 }
1994
1995 const MIN_NON_ZERO_DURATION: Duration = Duration::new(0, 1);
1996 #[test_case(
1997 NonZeroNdpLifetime::Infinite,
1998 NonZeroDuration::new(MIN_NON_ZERO_DURATION).unwrap(),
1999 NonZeroDuration::new(MIN_NON_ZERO_DURATION).unwrap()
2000 )]
2001 #[test_case(
2002 NonZeroNdpLifetime::Infinite,
2003 NonZeroDuration::new(Duration::MAX).unwrap(),
2004 NonZeroDuration::new(Duration::MAX).unwrap()
2005 )]
2006 #[test_case(
2007 NonZeroNdpLifetime::Finite(NonZeroDuration::new(
2008 Duration::from_secs(2)).unwrap()
2009 ),
2010 NonZeroDuration::new(Duration::from_secs(1)).unwrap(),
2011 NonZeroDuration::new(Duration::from_secs(1)).unwrap()
2012 )]
2013 #[test_case(
2014 NonZeroNdpLifetime::Finite(NonZeroDuration::new(
2015 Duration::from_secs(3)).unwrap()
2016 ),
2017 NonZeroDuration::new(Duration::from_secs(4)).unwrap(),
2018 NonZeroDuration::new(Duration::from_secs(3)).unwrap()
2019 )]
2020 fn non_zero_ndp_lifetime_min_finite_duration(
2021 lifetime: NonZeroNdpLifetime,
2022 duration: NonZeroDuration,
2023 expected: NonZeroDuration,
2024 ) {
2025 assert_eq!(lifetime.min_finite_duration(duration), expected)
2026 }
2027}