1#![deny(missing_docs)]
2
3use byteorder::{ByteOrder, NetworkEndian};
4use core::fmt;
5
6use super::{Error, Result};
7use crate::wire::HardwareAddress;
8use crate::wire::ip::pretty_print_ip_payload;
9
10pub use super::IpProtocol as Protocol;
11
12pub const MIN_MTU: usize = 1280;
16
17pub const ADDR_SIZE: usize = 16;
21
22pub const LINK_LOCAL_ALL_NODES: Address = Address::new(0xff02, 0, 0, 0, 0, 0, 0, 1);
26
27pub const LINK_LOCAL_ALL_ROUTERS: Address = Address::new(0xff02, 0, 0, 0, 0, 0, 0, 2);
31
32pub const LINK_LOCAL_ALL_MLDV2_ROUTERS: Address = Address::new(0xff02, 0, 0, 0, 0, 0, 0, 0x16);
36
37pub const LINK_LOCAL_ALL_RPL_NODES: Address = Address::new(0xff02, 0, 0, 0, 0, 0, 0, 0x1a);
41
42#[repr(u8)]
46#[derive(Debug, Clone, Copy, PartialEq, Eq)]
47pub(crate) enum MulticastScope {
48 InterfaceLocal = 0x1,
50 LinkLocal = 0x2,
52 AdminLocal = 0x4,
54 SiteLocal = 0x5,
56 OrganizationLocal = 0x8,
58 Global = 0xE,
60 Unknown = 0xFF,
62}
63
64impl From<u8> for MulticastScope {
65 fn from(value: u8) -> Self {
66 match value {
67 0x1 => Self::InterfaceLocal,
68 0x2 => Self::LinkLocal,
69 0x4 => Self::AdminLocal,
70 0x5 => Self::SiteLocal,
71 0x8 => Self::OrganizationLocal,
72 0xE => Self::Global,
73 _ => Self::Unknown,
74 }
75 }
76}
77
78pub use core::net::Ipv6Addr as Address;
79
80pub(crate) trait AddressExt {
81 fn from_link_prefix(
83 link_prefix: &Cidr,
84 interface_identifier: HardwareAddress,
85 ) -> Option<Address>;
86
87 fn x_is_unicast(&self) -> bool;
93
94 fn is_global_unicast(&self) -> bool;
98
99 fn is_link_local(&self) -> bool;
103
104 fn mask(&self, mask: u8) -> [u8; ADDR_SIZE];
109
110 fn solicited_node(&self) -> Address;
116
117 fn x_multicast_scope(&self) -> MulticastScope;
121
122 fn is_solicited_node_multicast(&self) -> bool;
126
127 fn prefix_len(&self) -> Option<u8>;
130}
131
132impl AddressExt for Address {
133 fn from_link_prefix(
134 link_prefix: &Cidr,
135 interface_identifier: HardwareAddress,
136 ) -> Option<Address> {
137 if let Some(eui64) = interface_identifier.as_eui_64() {
138 if link_prefix.prefix_len() != 64 {
139 return None;
140 }
141 let mut bytes = [0; 16];
142 bytes[0..8].copy_from_slice(&link_prefix.address().octets()[0..8]);
143 bytes[8..16].copy_from_slice(&eui64);
144 Some(Address::from_octets(bytes))
145 } else {
146 None
147 }
148 }
149
150 fn x_is_unicast(&self) -> bool {
151 !(self.is_multicast() || self.is_unspecified())
152 }
153
154 fn is_global_unicast(&self) -> bool {
155 (self.octets()[0] >> 5) == 0b001
156 }
157
158 fn is_link_local(&self) -> bool {
159 self.octets()[0..8] == [0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
160 }
161
162 fn mask(&self, mask: u8) -> [u8; ADDR_SIZE] {
163 assert!(mask <= 128);
164 let mut bytes = [0u8; ADDR_SIZE];
165 let idx = (mask as usize) / 8;
166 let modulus = (mask as usize) % 8;
167 let octets = self.octets();
168 let (first, second) = octets.split_at(idx);
169 bytes[0..idx].copy_from_slice(first);
170 if idx < ADDR_SIZE {
171 let part = second[0];
172 bytes[idx] = part & (!(0xff >> modulus) as u8);
173 }
174 bytes
175 }
176
177 fn solicited_node(&self) -> Address {
178 assert!(self.x_is_unicast());
179 let o = self.octets();
180 Address::from([
181 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, o[13],
182 o[14], o[15],
183 ])
184 }
185
186 fn x_multicast_scope(&self) -> MulticastScope {
187 if self.is_multicast() {
188 return MulticastScope::from(self.octets()[1] & 0b1111);
189 }
190
191 if self.is_link_local() {
192 MulticastScope::LinkLocal
193 } else if self.is_unique_local() || self.is_global_unicast() {
194 MulticastScope::Global
197 } else {
198 MulticastScope::Unknown
199 }
200 }
201
202 fn is_solicited_node_multicast(&self) -> bool {
203 self.octets()[0..13]
204 == [
205 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF,
206 ]
207 }
208
209 fn prefix_len(&self) -> Option<u8> {
210 let mut ones = true;
211 let mut prefix_len = 0;
212 for byte in self.octets() {
213 let mut mask = 0x80;
214 for _ in 0..8 {
215 let one = byte & mask != 0;
216 if ones {
217 if one {
219 prefix_len += 1;
220 } else {
221 ones = false;
222 }
223 } else if one {
224 return None;
226 }
227 mask >>= 1;
228 }
229 }
230 Some(prefix_len)
231 }
232}
233
234#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
237pub struct Cidr {
238 address: Address,
239 prefix_len: u8,
240}
241
242impl Cidr {
243 pub const SOLICITED_NODE_PREFIX: Cidr = Cidr {
247 address: Address::new(0xff02, 0, 0, 0, 0, 1, 0xff00, 0),
248 prefix_len: 104,
249 };
250
251 pub const LINK_LOCAL_PREFIX: Cidr = Cidr {
253 address: Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 0),
254 prefix_len: 10,
255 };
256
257 pub const fn new(address: Address, prefix_len: u8) -> Cidr {
262 assert!(prefix_len <= 128);
263 Cidr {
264 address,
265 prefix_len,
266 }
267 }
268
269 pub fn from_link_prefix(
271 link_prefix: &Cidr,
272 interface_identifier: HardwareAddress,
273 ) -> Option<Self> {
274 Address::from_link_prefix(link_prefix, interface_identifier)
275 .map(|address| Self::new(address, link_prefix.prefix_len()))
276 }
277
278 pub const fn address(&self) -> Address {
280 self.address
281 }
282
283 pub const fn prefix_len(&self) -> u8 {
285 self.prefix_len
286 }
287
288 pub fn contains_addr(&self, addr: &Address) -> bool {
291 if self.prefix_len == 0 {
293 return true;
294 }
295
296 self.address.mask(self.prefix_len) == addr.mask(self.prefix_len)
297 }
298
299 pub fn contains_subnet(&self, subnet: &Cidr) -> bool {
302 self.prefix_len <= subnet.prefix_len && self.contains_addr(&subnet.address)
303 }
304}
305
306impl fmt::Display for Cidr {
307 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
308 write!(f, "{}/{}", self.address, self.prefix_len)
310 }
311}
312
313#[cfg(feature = "defmt")]
314impl defmt::Format for Cidr {
315 fn format(&self, f: defmt::Formatter) {
316 defmt::write!(f, "{}/{=u8}", self.address, self.prefix_len);
317 }
318}
319
320#[derive(Debug, PartialEq, Eq, Clone)]
322#[cfg_attr(feature = "defmt", derive(defmt::Format))]
323pub struct Packet<T: AsRef<[u8]>> {
324 buffer: T,
325}
326
327mod field {
353 use crate::wire::field::*;
354 pub const VER_TC_FLOW: Field = 0..4;
357 pub const LENGTH: Field = 4..6;
360 pub const NXT_HDR: usize = 6;
363 pub const HOP_LIMIT: usize = 7;
366 pub const SRC_ADDR: Field = 8..24;
368 pub const DST_ADDR: Field = 24..40;
370}
371
372pub const HEADER_LEN: usize = field::DST_ADDR.end;
374
375impl<T: AsRef<[u8]>> Packet<T> {
376 #[inline]
378 pub const fn new_unchecked(buffer: T) -> Packet<T> {
379 Packet { buffer }
380 }
381
382 #[inline]
387 pub fn new_checked(buffer: T) -> Result<Packet<T>> {
388 let packet = Self::new_unchecked(buffer);
389 packet.check_len()?;
390 Ok(packet)
391 }
392
393 #[inline]
400 pub fn check_len(&self) -> Result<()> {
401 let len = self.buffer.as_ref().len();
402 if len < field::DST_ADDR.end || len < self.total_len() {
403 Err(Error)
404 } else {
405 Ok(())
406 }
407 }
408
409 #[inline]
411 pub fn into_inner(self) -> T {
412 self.buffer
413 }
414
415 #[inline]
417 pub const fn header_len(&self) -> usize {
418 field::DST_ADDR.end
421 }
422
423 #[inline]
425 pub fn version(&self) -> u8 {
426 let data = self.buffer.as_ref();
427 data[field::VER_TC_FLOW.start] >> 4
428 }
429
430 #[inline]
432 pub fn traffic_class(&self) -> u8 {
433 let data = self.buffer.as_ref();
434 ((NetworkEndian::read_u16(&data[0..2]) & 0x0ff0) >> 4) as u8
435 }
436
437 #[inline]
439 pub fn flow_label(&self) -> u32 {
440 let data = self.buffer.as_ref();
441 NetworkEndian::read_u24(&data[1..4]) & 0x000fffff
442 }
443
444 #[inline]
446 pub fn payload_len(&self) -> u16 {
447 let data = self.buffer.as_ref();
448 NetworkEndian::read_u16(&data[field::LENGTH])
449 }
450
451 #[inline]
453 pub fn total_len(&self) -> usize {
454 self.header_len() + self.payload_len() as usize
455 }
456
457 #[inline]
459 pub fn next_header(&self) -> Protocol {
460 let data = self.buffer.as_ref();
461 Protocol::from(data[field::NXT_HDR])
462 }
463
464 #[inline]
466 pub fn hop_limit(&self) -> u8 {
467 let data = self.buffer.as_ref();
468 data[field::HOP_LIMIT]
469 }
470
471 #[inline]
473 pub fn src_addr(&self) -> Address {
474 let data = self.buffer.as_ref();
475 Address::from_octets(data[field::SRC_ADDR].try_into().unwrap())
476 }
477
478 #[inline]
480 pub fn dst_addr(&self) -> Address {
481 let data = self.buffer.as_ref();
482 Address::from_octets(data[field::DST_ADDR].try_into().unwrap())
483 }
484}
485
486impl<'a, T: AsRef<[u8]> + ?Sized> Packet<&'a T> {
487 #[inline]
489 pub fn payload(&self) -> &'a [u8] {
490 let data = self.buffer.as_ref();
491 let range = self.header_len()..self.total_len();
492 &data[range]
493 }
494}
495
496impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
497 #[inline]
499 pub fn set_version(&mut self, value: u8) {
500 let data = self.buffer.as_mut();
501 data[0] = (data[0] & 0x0f) | ((value & 0x0f) << 4);
504 }
505
506 #[inline]
508 pub fn set_traffic_class(&mut self, value: u8) {
509 let data = self.buffer.as_mut();
510 data[0] = (data[0] & 0xf0) | ((value & 0xf0) >> 4);
513 data[1] = (data[1] & 0x0f) | ((value & 0x0f) << 4);
516 }
517
518 #[inline]
520 pub fn set_flow_label(&mut self, value: u32) {
521 let data = self.buffer.as_mut();
522 let raw = (((data[1] & 0xf0) as u32) << 16) | (value & 0x0fffff);
524 NetworkEndian::write_u24(&mut data[1..4], raw);
525 }
526
527 #[inline]
529 pub fn set_payload_len(&mut self, value: u16) {
530 let data = self.buffer.as_mut();
531 NetworkEndian::write_u16(&mut data[field::LENGTH], value);
532 }
533
534 #[inline]
536 pub fn set_next_header(&mut self, value: Protocol) {
537 let data = self.buffer.as_mut();
538 data[field::NXT_HDR] = value.into();
539 }
540
541 #[inline]
543 pub fn set_hop_limit(&mut self, value: u8) {
544 let data = self.buffer.as_mut();
545 data[field::HOP_LIMIT] = value;
546 }
547
548 #[inline]
550 pub fn set_src_addr(&mut self, value: Address) {
551 let data = self.buffer.as_mut();
552 data[field::SRC_ADDR].copy_from_slice(&value.octets());
553 }
554
555 #[inline]
557 pub fn set_dst_addr(&mut self, value: Address) {
558 let data = self.buffer.as_mut();
559 data[field::DST_ADDR].copy_from_slice(&value.octets());
560 }
561
562 #[inline]
564 pub fn payload_mut(&mut self) -> &mut [u8] {
565 let range = self.header_len()..self.total_len();
566 let data = self.buffer.as_mut();
567 &mut data[range]
568 }
569}
570
571impl<T: AsRef<[u8]> + ?Sized> fmt::Display for Packet<&T> {
572 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
573 match Repr::parse(self) {
574 Ok(repr) => write!(f, "{repr}"),
575 Err(err) => {
576 write!(f, "IPv6 ({err})")?;
577 Ok(())
578 }
579 }
580 }
581}
582
583impl<T: AsRef<[u8]>> AsRef<[u8]> for Packet<T> {
584 fn as_ref(&self) -> &[u8] {
585 self.buffer.as_ref()
586 }
587}
588
589#[derive(Debug, PartialEq, Eq, Clone, Copy)]
591pub struct Repr {
592 pub src_addr: Address,
594 pub dst_addr: Address,
596 pub next_header: Protocol,
598 pub payload_len: usize,
600 pub hop_limit: u8,
602}
603
604impl Repr {
605 pub fn parse<T: AsRef<[u8]> + ?Sized>(packet: &Packet<&T>) -> Result<Repr> {
607 packet.check_len()?;
609 if packet.version() != 6 {
610 return Err(Error);
611 }
612 Ok(Repr {
613 src_addr: packet.src_addr(),
614 dst_addr: packet.dst_addr(),
615 next_header: packet.next_header(),
616 payload_len: packet.payload_len() as usize,
617 hop_limit: packet.hop_limit(),
618 })
619 }
620
621 pub const fn buffer_len(&self) -> usize {
623 field::DST_ADDR.end
625 }
626
627 pub fn emit<T: AsRef<[u8]> + AsMut<[u8]>>(&self, packet: &mut Packet<T>) {
629 packet.set_version(6);
632 packet.set_traffic_class(0);
633 packet.set_flow_label(0);
634 packet.set_payload_len(self.payload_len as u16);
635 packet.set_hop_limit(self.hop_limit);
636 packet.set_next_header(self.next_header);
637 packet.set_src_addr(self.src_addr);
638 packet.set_dst_addr(self.dst_addr);
639 }
640}
641
642impl fmt::Display for Repr {
643 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
644 write!(
645 f,
646 "IPv6 src={} dst={} nxt_hdr={} hop_limit={}",
647 self.src_addr, self.dst_addr, self.next_header, self.hop_limit
648 )
649 }
650}
651
652#[cfg(feature = "defmt")]
653impl defmt::Format for Repr {
654 fn format(&self, fmt: defmt::Formatter) {
655 defmt::write!(
656 fmt,
657 "IPv6 src={} dst={} nxt_hdr={} hop_limit={}",
658 self.src_addr,
659 self.dst_addr,
660 self.next_header,
661 self.hop_limit
662 )
663 }
664}
665
666use crate::wire::pretty_print::{PrettyIndent, PrettyPrint};
667
668impl<T: AsRef<[u8]>> PrettyPrint for Packet<T> {
671 fn pretty_print(
672 buffer: &dyn AsRef<[u8]>,
673 f: &mut fmt::Formatter,
674 indent: &mut PrettyIndent,
675 ) -> fmt::Result {
676 let (ip_repr, payload) = match Packet::new_checked(buffer) {
677 Err(err) => return write!(f, "{indent}({err})"),
678 Ok(ip_packet) => match Repr::parse(&ip_packet) {
679 Err(_) => return Ok(()),
680 Ok(ip_repr) => {
681 write!(f, "{indent}{ip_repr}")?;
682 (ip_repr, ip_packet.payload())
683 }
684 },
685 };
686
687 pretty_print_ip_payload(f, indent, ip_repr, payload)
688 }
689}
690
691#[cfg(test)]
692pub(crate) mod test {
693 use super::*;
694 use crate::wire::pretty_print::PrettyPrinter;
695
696 #[allow(unused)]
697 pub(crate) const MOCK_IP_ADDR_1: Address = Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 1);
698 #[allow(unused)]
699 pub(crate) const MOCK_IP_ADDR_2: Address = Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 2);
700 #[allow(unused)]
701 pub(crate) const MOCK_IP_ADDR_3: Address = Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 3);
702 #[allow(unused)]
703 pub(crate) const MOCK_IP_ADDR_4: Address = Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 4);
704 #[allow(unused)]
705 pub(crate) const MOCK_UNSPECIFIED: Address = Address::UNSPECIFIED;
706
707 const LINK_LOCAL_ADDR: Address = Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 1);
708 const UNIQUE_LOCAL_ADDR: Address = Address::new(0xfd00, 0, 0, 201, 1, 1, 1, 1);
709 const GLOBAL_UNICAST_ADDR: Address = Address::new(0x2001, 0xdb8, 0x3, 0, 0, 0, 0, 1);
710
711 const TEST_SOL_NODE_MCAST_ADDR: Address = Address::new(0xff02, 0, 0, 0, 0, 1, 0xff01, 101);
712
713 #[test]
714 fn test_basic_multicast() {
715 assert!(!LINK_LOCAL_ALL_ROUTERS.is_unspecified());
716 assert!(LINK_LOCAL_ALL_ROUTERS.is_multicast());
717 assert!(!LINK_LOCAL_ALL_ROUTERS.is_link_local());
718 assert!(!LINK_LOCAL_ALL_ROUTERS.is_loopback());
719 assert!(!LINK_LOCAL_ALL_ROUTERS.is_unique_local());
720 assert!(!LINK_LOCAL_ALL_ROUTERS.is_global_unicast());
721 assert!(!LINK_LOCAL_ALL_ROUTERS.is_solicited_node_multicast());
722 assert!(!LINK_LOCAL_ALL_NODES.is_unspecified());
723 assert!(LINK_LOCAL_ALL_NODES.is_multicast());
724 assert!(!LINK_LOCAL_ALL_NODES.is_link_local());
725 assert!(!LINK_LOCAL_ALL_NODES.is_loopback());
726 assert!(!LINK_LOCAL_ALL_NODES.is_unique_local());
727 assert!(!LINK_LOCAL_ALL_NODES.is_global_unicast());
728 assert!(!LINK_LOCAL_ALL_NODES.is_solicited_node_multicast());
729 }
730
731 #[test]
732 fn test_basic_link_local() {
733 assert!(!LINK_LOCAL_ADDR.is_unspecified());
734 assert!(!LINK_LOCAL_ADDR.is_multicast());
735 assert!(LINK_LOCAL_ADDR.is_link_local());
736 assert!(!LINK_LOCAL_ADDR.is_loopback());
737 assert!(!LINK_LOCAL_ADDR.is_unique_local());
738 assert!(!LINK_LOCAL_ADDR.is_global_unicast());
739 assert!(!LINK_LOCAL_ADDR.is_solicited_node_multicast());
740 }
741
742 #[test]
743 fn test_basic_loopback() {
744 assert!(!Address::LOCALHOST.is_unspecified());
745 assert!(!Address::LOCALHOST.is_multicast());
746 assert!(!Address::LOCALHOST.is_link_local());
747 assert!(Address::LOCALHOST.is_loopback());
748 assert!(!Address::LOCALHOST.is_unique_local());
749 assert!(!Address::LOCALHOST.is_global_unicast());
750 assert!(!Address::LOCALHOST.is_solicited_node_multicast());
751 }
752
753 #[test]
754 fn test_unique_local() {
755 assert!(!UNIQUE_LOCAL_ADDR.is_unspecified());
756 assert!(!UNIQUE_LOCAL_ADDR.is_multicast());
757 assert!(!UNIQUE_LOCAL_ADDR.is_link_local());
758 assert!(!UNIQUE_LOCAL_ADDR.is_loopback());
759 assert!(UNIQUE_LOCAL_ADDR.is_unique_local());
760 assert!(!UNIQUE_LOCAL_ADDR.is_global_unicast());
761 assert!(!UNIQUE_LOCAL_ADDR.is_solicited_node_multicast());
762 }
763
764 #[test]
765 fn test_global_unicast() {
766 assert!(!GLOBAL_UNICAST_ADDR.is_unspecified());
767 assert!(!GLOBAL_UNICAST_ADDR.is_multicast());
768 assert!(!GLOBAL_UNICAST_ADDR.is_link_local());
769 assert!(!GLOBAL_UNICAST_ADDR.is_loopback());
770 assert!(!GLOBAL_UNICAST_ADDR.is_unique_local());
771 assert!(GLOBAL_UNICAST_ADDR.is_global_unicast());
772 assert!(!GLOBAL_UNICAST_ADDR.is_solicited_node_multicast());
773 }
774
775 #[test]
776 fn test_sollicited_node_multicast() {
777 assert!(!TEST_SOL_NODE_MCAST_ADDR.is_unspecified());
778 assert!(TEST_SOL_NODE_MCAST_ADDR.is_multicast());
779 assert!(!TEST_SOL_NODE_MCAST_ADDR.is_link_local());
780 assert!(!TEST_SOL_NODE_MCAST_ADDR.is_loopback());
781 assert!(!TEST_SOL_NODE_MCAST_ADDR.is_unique_local());
782 assert!(!TEST_SOL_NODE_MCAST_ADDR.is_global_unicast());
783 assert!(TEST_SOL_NODE_MCAST_ADDR.is_solicited_node_multicast());
784 }
785
786 #[test]
787 fn test_mask() {
788 let addr = Address::new(0x0123, 0x4567, 0x89ab, 0, 0, 0, 0, 1);
789 assert_eq!(
790 addr.mask(11),
791 [0x01, 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
792 );
793 assert_eq!(
794 addr.mask(15),
795 [0x01, 0x22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
796 );
797 assert_eq!(
798 addr.mask(26),
799 [0x01, 0x23, 0x45, 0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
800 );
801 assert_eq!(
802 addr.mask(128),
803 [
804 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
805 ]
806 );
807 assert_eq!(
808 addr.mask(127),
809 [
810 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
811 ]
812 );
813 }
814
815 #[test]
816 fn test_cidr() {
817 let cidr = Cidr::new(LINK_LOCAL_ADDR, 56);
821
822 let inside_subnet = [
823 [
825 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
826 0x00, 0x02,
827 ],
828 [
830 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66,
831 0x77, 0x88,
832 ],
833 [
835 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
836 0x00, 0x00,
837 ],
838 [
840 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
841 0x00, 0xff,
842 ],
843 ];
844
845 let outside_subnet = [
846 [
848 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
849 0x00, 0x01,
850 ],
851 [
853 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
854 0x00, 0x01,
855 ],
856 [
858 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
859 0x00, 0x01,
860 ],
861 [
863 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
864 0x00, 0x02,
865 ],
866 ];
867
868 let subnets = [
869 (
871 [
872 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff,
873 0xff, 0xff, 0xff,
874 ],
875 65,
876 ),
877 (
879 [
880 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
881 0x00, 0x00, 0x01,
882 ],
883 128,
884 ),
885 (
887 [
888 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12,
889 0x34, 0x56, 0x78,
890 ],
891 96,
892 ),
893 ];
894
895 let not_subnets = [
896 (
898 [
899 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff,
900 0xff, 0xff, 0xff,
901 ],
902 55,
903 ),
904 (
906 [
907 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff,
908 0xff, 0xff, 0xff,
909 ],
910 56,
911 ),
912 (
914 [
915 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff,
916 0xff, 0xff, 0xff,
917 ],
918 57,
919 ),
920 (
922 [
923 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
924 0x00, 0x00, 0x01,
925 ],
926 128,
927 ),
928 ];
929
930 for addr in inside_subnet.iter().map(|a| Address::from_octets(*a)) {
931 assert!(cidr.contains_addr(&addr));
932 }
933
934 for addr in outside_subnet.iter().map(|a| Address::from_octets(*a)) {
935 assert!(!cidr.contains_addr(&addr));
936 }
937
938 for subnet in subnets.iter().map(|&(a, p)| Cidr::new(Address::from(a), p)) {
939 assert!(cidr.contains_subnet(&subnet));
940 }
941
942 for subnet in not_subnets
943 .iter()
944 .map(|&(a, p)| Cidr::new(Address::from(a), p))
945 {
946 assert!(!cidr.contains_subnet(&subnet));
947 }
948
949 let cidr_without_prefix = Cidr::new(LINK_LOCAL_ADDR, 0);
950 assert!(cidr_without_prefix.contains_addr(&Address::LOCALHOST));
951 }
952
953 #[test]
954 fn test_from_eui_64() {
955 #[cfg(feature = "medium-ethernet")]
956 use crate::wire::EthernetAddress;
957 #[cfg(feature = "medium-ieee802154")]
958 use crate::wire::Ieee802154Address;
959 let tests: std::vec::Vec<(HardwareAddress, Address)> = vec![
960 #[cfg(feature = "medium-ethernet")]
961 (
962 HardwareAddress::Ethernet(EthernetAddress::from_bytes(&[
963 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
964 ])),
965 Address::new(0x2001, 0xdb8, 0x3, 0x0, 0xa8bb, 0xccff, 0xfedd, 0xeeff),
966 ),
967 #[cfg(feature = "medium-ieee802154")]
968 (
969 HardwareAddress::Ieee802154(Ieee802154Address::from_bytes(&[
970 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
971 ])),
972 Address::new(0x2001, 0xdb8, 0x3, 0x0, 0x0211, 0x2233, 0x4455, 0x6677),
973 ),
974 ];
975
976 let prefix = Cidr::new(GLOBAL_UNICAST_ADDR.mask(64).into(), 64);
977 let wrong_prefix = Cidr::new(GLOBAL_UNICAST_ADDR.mask(72).into(), 72);
978
979 for (hardware, result) in tests {
980 let generated = Address::from_link_prefix(&prefix, hardware).unwrap();
981 assert!(prefix.contains_addr(&generated));
982 assert_eq!(generated, result);
983 assert!(Address::from_link_prefix(&wrong_prefix, hardware).is_none());
984
985 let generated = Cidr::from_link_prefix(&prefix, hardware).unwrap();
986 assert!(prefix.contains_subnet(&generated));
987 assert_eq!(generated.address(), result);
988 assert!(Cidr::from_link_prefix(&wrong_prefix, hardware).is_none());
989 }
990 }
991
992 #[test]
993 fn test_scope() {
994 use super::*;
995 assert_eq!(
996 Address::new(0xff01, 0, 0, 0, 0, 0, 0, 1).x_multicast_scope(),
997 MulticastScope::InterfaceLocal
998 );
999 assert_eq!(
1000 Address::new(0xff02, 0, 0, 0, 0, 0, 0, 1).x_multicast_scope(),
1001 MulticastScope::LinkLocal
1002 );
1003 assert_eq!(
1004 Address::new(0xff03, 0, 0, 0, 0, 0, 0, 1).x_multicast_scope(),
1005 MulticastScope::Unknown
1006 );
1007 assert_eq!(
1008 Address::new(0xff04, 0, 0, 0, 0, 0, 0, 1).x_multicast_scope(),
1009 MulticastScope::AdminLocal
1010 );
1011 assert_eq!(
1012 Address::new(0xff05, 0, 0, 0, 0, 0, 0, 1).x_multicast_scope(),
1013 MulticastScope::SiteLocal
1014 );
1015 assert_eq!(
1016 Address::new(0xff08, 0, 0, 0, 0, 0, 0, 1).x_multicast_scope(),
1017 MulticastScope::OrganizationLocal
1018 );
1019 assert_eq!(
1020 Address::new(0xff0e, 0, 0, 0, 0, 0, 0, 1).x_multicast_scope(),
1021 MulticastScope::Global
1022 );
1023
1024 assert_eq!(
1025 LINK_LOCAL_ALL_NODES.x_multicast_scope(),
1026 MulticastScope::LinkLocal
1027 );
1028
1029 assert_eq!(
1031 LINK_LOCAL_ADDR.x_multicast_scope(),
1032 MulticastScope::LinkLocal
1033 );
1034 assert_eq!(
1035 GLOBAL_UNICAST_ADDR.x_multicast_scope(),
1036 MulticastScope::Global
1037 );
1038 assert_eq!(
1039 UNIQUE_LOCAL_ADDR.x_multicast_scope(),
1040 MulticastScope::Global
1041 );
1042 }
1043
1044 static REPR_PACKET_BYTES: [u8; 52] = [
1045 0x60, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x11, 0x40, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
1046 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00,
1047 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00,
1048 0x0c, 0x02, 0x4e, 0xff, 0xff, 0xff, 0xff,
1049 ];
1050 static REPR_PAYLOAD_BYTES: [u8; 12] = [
1051 0x00, 0x01, 0x00, 0x02, 0x00, 0x0c, 0x02, 0x4e, 0xff, 0xff, 0xff, 0xff,
1052 ];
1053
1054 const fn packet_repr() -> Repr {
1055 Repr {
1056 src_addr: Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 1),
1057 dst_addr: LINK_LOCAL_ALL_NODES,
1058 next_header: Protocol::Udp,
1059 payload_len: 12,
1060 hop_limit: 64,
1061 }
1062 }
1063
1064 #[test]
1065 fn test_packet_deconstruction() {
1066 let packet = Packet::new_unchecked(&REPR_PACKET_BYTES[..]);
1067 assert_eq!(packet.check_len(), Ok(()));
1068 assert_eq!(packet.version(), 6);
1069 assert_eq!(packet.traffic_class(), 0);
1070 assert_eq!(packet.flow_label(), 0);
1071 assert_eq!(packet.total_len(), 0x34);
1072 assert_eq!(packet.payload_len() as usize, REPR_PAYLOAD_BYTES.len());
1073 assert_eq!(packet.next_header(), Protocol::Udp);
1074 assert_eq!(packet.hop_limit(), 0x40);
1075 assert_eq!(packet.src_addr(), Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 1));
1076 assert_eq!(packet.dst_addr(), LINK_LOCAL_ALL_NODES);
1077 assert_eq!(packet.payload(), &REPR_PAYLOAD_BYTES[..]);
1078 }
1079
1080 #[test]
1081 fn test_packet_construction() {
1082 let mut bytes = [0xff; 52];
1083 let mut packet = Packet::new_unchecked(&mut bytes[..]);
1084 packet.set_version(6);
1088 assert_eq!(packet.version(), 6);
1089 packet.set_traffic_class(0x99);
1090 assert_eq!(packet.version(), 6);
1091 assert_eq!(packet.traffic_class(), 0x99);
1092 packet.set_flow_label(0x54321);
1093 assert_eq!(packet.traffic_class(), 0x99);
1094 assert_eq!(packet.flow_label(), 0x54321);
1095 packet.set_payload_len(0xc);
1096 packet.set_next_header(Protocol::Udp);
1097 packet.set_hop_limit(0xfe);
1098 packet.set_src_addr(LINK_LOCAL_ALL_ROUTERS);
1099 packet.set_dst_addr(LINK_LOCAL_ALL_NODES);
1100 packet
1101 .payload_mut()
1102 .copy_from_slice(&REPR_PAYLOAD_BYTES[..]);
1103 let mut expected_bytes = [
1104 0x69, 0x95, 0x43, 0x21, 0x00, 0x0c, 0x11, 0xfe, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00,
1105 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x02, 0x00, 0x00,
1106 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
1107 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1108 ];
1109 let start = expected_bytes.len() - REPR_PAYLOAD_BYTES.len();
1110 expected_bytes[start..].copy_from_slice(&REPR_PAYLOAD_BYTES[..]);
1111 assert_eq!(packet.check_len(), Ok(()));
1112 assert_eq!(&*packet.into_inner(), &expected_bytes[..]);
1113 }
1114
1115 #[test]
1116 fn test_overlong() {
1117 let mut bytes = vec![];
1118 bytes.extend(&REPR_PACKET_BYTES[..]);
1119 bytes.push(0);
1120
1121 assert_eq!(
1122 Packet::new_unchecked(&bytes).payload().len(),
1123 REPR_PAYLOAD_BYTES.len()
1124 );
1125 assert_eq!(
1126 Packet::new_unchecked(&mut bytes).payload_mut().len(),
1127 REPR_PAYLOAD_BYTES.len()
1128 );
1129 }
1130
1131 #[test]
1132 fn test_total_len_overflow() {
1133 let mut bytes = vec![];
1134 bytes.extend(&REPR_PACKET_BYTES[..]);
1135 Packet::new_unchecked(&mut bytes).set_payload_len(0x80);
1136
1137 assert_eq!(Packet::new_checked(&bytes).unwrap_err(), Error);
1138 }
1139
1140 #[test]
1141 fn test_repr_parse_valid() {
1142 let packet = Packet::new_unchecked(&REPR_PACKET_BYTES[..]);
1143 let repr = Repr::parse(&packet).unwrap();
1144 assert_eq!(repr, packet_repr());
1145 }
1146
1147 #[test]
1148 fn test_repr_parse_bad_version() {
1149 let mut bytes = [0; 40];
1150 let mut packet = Packet::new_unchecked(&mut bytes[..]);
1151 packet.set_version(4);
1152 packet.set_payload_len(0);
1153 let packet = Packet::new_unchecked(&*packet.into_inner());
1154 assert_eq!(Repr::parse(&packet), Err(Error));
1155 }
1156
1157 #[test]
1158 fn test_repr_parse_smaller_than_header() {
1159 let mut bytes = [0; 40];
1160 let mut packet = Packet::new_unchecked(&mut bytes[..]);
1161 packet.set_version(6);
1162 packet.set_payload_len(39);
1163 let packet = Packet::new_unchecked(&*packet.into_inner());
1164 assert_eq!(Repr::parse(&packet), Err(Error));
1165 }
1166
1167 #[test]
1168 fn test_repr_parse_smaller_than_payload() {
1169 let mut bytes = [0; 40];
1170 let mut packet = Packet::new_unchecked(&mut bytes[..]);
1171 packet.set_version(6);
1172 packet.set_payload_len(1);
1173 let packet = Packet::new_unchecked(&*packet.into_inner());
1174 assert_eq!(Repr::parse(&packet), Err(Error));
1175 }
1176
1177 #[test]
1178 fn test_basic_repr_emit() {
1179 let repr = packet_repr();
1180 let mut bytes = vec![0xff; repr.buffer_len() + REPR_PAYLOAD_BYTES.len()];
1181 let mut packet = Packet::new_unchecked(&mut bytes);
1182 repr.emit(&mut packet);
1183 packet.payload_mut().copy_from_slice(&REPR_PAYLOAD_BYTES);
1184 assert_eq!(&*packet.into_inner(), &REPR_PACKET_BYTES[..]);
1185 }
1186
1187 #[test]
1188 fn test_pretty_print() {
1189 assert_eq!(
1190 format!(
1191 "{}",
1192 PrettyPrinter::<Packet<&'static [u8]>>::new("\n", &&REPR_PACKET_BYTES[..])
1193 ),
1194 "\nIPv6 src=fe80::1 dst=ff02::1 nxt_hdr=UDP hop_limit=64\n \\ UDP src=1 dst=2 len=4"
1195 );
1196 }
1197}