Эх сурвалжийг харах

Merge pull request #994 from smoltcp-rs/core-ip

wire: use core::net types for IP addresses.
Dario Nieuwenhuis 5 сар өмнө
parent
commit
7acf1ac71b
51 өөрчлөгдсөн 765 нэмэгдсэн , 1391 устгасан
  1. 2 2
      Cargo.toml
  2. 1 1
      README.md
  3. 8 12
      benches/bench.rs
  4. 1 1
      ci.sh
  5. 0 1
      examples/loopback.rs
  6. 2 4
      examples/multicast.rs
  7. 6 9
      examples/multicast6.rs
  8. 5 5
      src/iface/fragmentation.rs
  9. 3 3
      src/iface/interface/ipv4.rs
  10. 19 18
      src/iface/interface/ipv6.rs
  11. 24 19
      src/iface/interface/mod.rs
  12. 2 4
      src/iface/interface/multicast.rs
  13. 2 1
      src/iface/interface/sixlowpan.rs
  14. 57 49
      src/iface/interface/tests/ipv4.rs
  15. 65 67
      src/iface/interface/tests/ipv6.rs
  16. 1 1
      src/iface/interface/tests/mod.rs
  17. 17 34
      src/iface/interface/tests/sixlowpan.rs
  18. 14 25
      src/iface/route.rs
  19. 5 6
      src/iface/rpl/of0.rs
  20. 8 11
      src/iface/rpl/parents.rs
  21. 1 5
      src/iface/rpl/relations.rs
  22. 1 1
      src/lib.rs
  23. 1 1
      src/macros.rs
  24. 9 127
      src/parsers.rs
  25. 2 2
      src/phy/fault_injector.rs
  26. 12 11
      src/socket/dhcpv4.rs
  27. 4 4
      src/socket/dns.rs
  28. 6 8
      src/socket/icmp.rs
  29. 4 10
      src/socket/raw.rs
  30. 28 24
      src/socket/tcp.rs
  31. 24 20
      src/socket/udp.rs
  32. 3 4
      src/wire/arp.rs
  33. 21 21
      src/wire/dhcpv4.rs
  34. 2 2
      src/wire/dns.rs
  35. 8 16
      src/wire/icmpv6.rs
  36. 1 1
      src/wire/ieee802154.rs
  37. 2 2
      src/wire/igmp.rs
  38. 19 58
      src/wire/ip.rs
  39. 148 211
      src/wire/ipv4.rs
  40. 155 518
      src/wire/ipv6.rs
  41. 5 5
      src/wire/ipv6routing.rs
  42. 23 29
      src/wire/mld.rs
  43. 12 3
      src/wire/mod.rs
  44. 5 7
      src/wire/ndisc.rs
  45. 2 2
      src/wire/ndiscoption.rs
  46. 9 11
      src/wire/rpl.rs
  47. 8 8
      src/wire/sixlowpan/iphc.rs
  48. 1 0
      src/wire/sixlowpan/mod.rs
  49. 2 2
      src/wire/sixlowpan/nhc.rs
  50. 3 3
      src/wire/tcp.rs
  51. 2 2
      src/wire/udp.rs

+ 2 - 2
Cargo.toml

@@ -2,7 +2,7 @@
 name = "smoltcp"
 version = "0.11.0"
 edition = "2021"
-rust-version = "1.77"
+rust-version = "1.80"
 authors = ["whitequark <[email protected]>"]
 description = "A TCP/IP stack designed for bare-metal, real-time systems without a heap."
 documentation = "https://docs.rs/smoltcp/"
@@ -25,7 +25,7 @@ byteorder = { version = "1.0", default-features = false }
 log = { version = "0.4.4", default-features = false, optional = true }
 libc = { version = "0.2.18", optional = true }
 bitflags = { version = "1.0", default-features = false }
-defmt = { version = "0.3", optional = true }
+defmt = { version = "0.3.8", optional = true, features = ["ip_in_core"] }
 cfg-if = "1.0.0"
 heapless = "0.8"
 

+ 1 - 1
README.md

@@ -12,7 +12,7 @@ include complicated compile-time computations, such as macro or type tricks, eve
 at cost of performance degradation.
 
 _smoltcp_ does not need heap allocation *at all*, is [extensively documented][docs],
-and compiles on stable Rust 1.77 and later.
+and compiles on stable Rust 1.80 and later.
 
 _smoltcp_ achieves [~Gbps of throughput](#examplesbenchmarkrs) when tested against
 the Linux TCP stack in loopback mode.

+ 8 - 12
benches/bench.rs

@@ -13,18 +13,14 @@ mod wire {
     extern crate test;
 
     #[cfg(feature = "proto-ipv6")]
-    const SRC_ADDR: IpAddress = IpAddress::Ipv6(Ipv6Address([
-        0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
-    ]));
+    const SRC_ADDR: IpAddress = IpAddress::Ipv6(Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 1));
     #[cfg(feature = "proto-ipv6")]
-    const DST_ADDR: IpAddress = IpAddress::Ipv6(Ipv6Address([
-        0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,
-    ]));
+    const DST_ADDR: IpAddress = IpAddress::Ipv6(Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 2));
 
     #[cfg(all(not(feature = "proto-ipv6"), feature = "proto-ipv4"))]
-    const SRC_ADDR: IpAddress = IpAddress::Ipv4(Ipv4Address([192, 168, 1, 1]));
+    const SRC_ADDR: IpAddress = IpAddress::Ipv4(Ipv4Address::new(192, 168, 1, 1));
     #[cfg(all(not(feature = "proto-ipv6"), feature = "proto-ipv4"))]
-    const DST_ADDR: IpAddress = IpAddress::Ipv4(Ipv4Address([192, 168, 1, 2]));
+    const DST_ADDR: IpAddress = IpAddress::Ipv4(Ipv4Address::new(192, 168, 1, 2));
 
     #[bench]
     #[cfg(any(feature = "proto-ipv6", feature = "proto-ipv4"))]
@@ -84,8 +80,8 @@ mod wire {
     #[cfg(feature = "proto-ipv4")]
     fn bench_emit_ipv4(b: &mut test::Bencher) {
         let repr = Ipv4Repr {
-            src_addr: Ipv4Address([192, 168, 1, 1]),
-            dst_addr: Ipv4Address([192, 168, 1, 2]),
+            src_addr: Ipv4Address::new(192, 168, 1, 1),
+            dst_addr: Ipv4Address::new(192, 168, 1, 2),
             next_header: IpProtocol::Tcp,
             payload_len: 100,
             hop_limit: 64,
@@ -102,8 +98,8 @@ mod wire {
     #[cfg(feature = "proto-ipv6")]
     fn bench_emit_ipv6(b: &mut test::Bencher) {
         let repr = Ipv6Repr {
-            src_addr: Ipv6Address([0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]),
-            dst_addr: Ipv6Address([0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2]),
+            src_addr: Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 1),
+            dst_addr: Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 2),
             next_header: IpProtocol::Tcp,
             payload_len: 100,
             hop_limit: 64,

+ 1 - 1
ci.sh

@@ -4,7 +4,7 @@ set -eox pipefail
 
 export DEFMT_LOG=trace
 
-MSRV="1.77.0"
+MSRV="1.80.0"
 
 RUSTC_VERSIONS=(
     $MSRV

+ 0 - 1
examples/loopback.rs

@@ -3,7 +3,6 @@
 #![allow(clippy::collapsible_if)]
 
 #[cfg(feature = "std")]
-#[allow(dead_code)]
 mod utils;
 
 use core::str;

+ 2 - 4
examples/multicast.rs

@@ -12,7 +12,7 @@ use smoltcp::wire::{
 };
 
 const MDNS_PORT: u16 = 5353;
-const MDNS_GROUP: [u8; 4] = [224, 0, 0, 251];
+const MDNS_GROUP: Ipv4Address = Ipv4Address::new(224, 0, 0, 251);
 
 fn main() {
     utils::setup_logging("warn");
@@ -81,9 +81,7 @@ fn main() {
     let udp_handle = sockets.add(udp_socket);
 
     // Join a multicast group to receive mDNS traffic
-    iface
-        .join_multicast_group(Ipv4Address::from_bytes(&MDNS_GROUP))
-        .unwrap();
+    iface.join_multicast_group(MDNS_GROUP).unwrap();
 
     loop {
         let timestamp = Instant::now();

+ 6 - 9
examples/multicast6.rs

@@ -19,9 +19,9 @@ use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr, Ipv6Address};
 // will send packets to the multicast group we join below on tap0.
 
 const PORT: u16 = 8123;
-const GROUP: [u16; 8] = [0xff02, 0, 0, 0, 0, 0, 0, 0x1234];
-const LOCAL_ADDR: [u16; 8] = [0xfe80, 0, 0, 0, 0, 0, 0, 0x101];
-const ROUTER_ADDR: [u16; 8] = [0xfe80, 0, 0, 0, 0, 0, 0, 0x100];
+const GROUP: Ipv6Address = Ipv6Address::new(0xff02, 0, 0, 0, 0, 0, 0, 0x1234);
+const LOCAL_ADDR: Ipv6Address = Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 0x101);
+const ROUTER_ADDR: Ipv6Address = Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 0x100);
 
 fn main() {
     utils::setup_logging("warn");
@@ -37,7 +37,6 @@ fn main() {
         utils::parse_middleware_options(&mut matches, device, /*loopback=*/ false);
 
     // Create interface
-    let local_addr = Ipv6Address::from_parts(&LOCAL_ADDR);
     let ethernet_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x02]);
     let mut config = match device.capabilities().medium {
         Medium::Ethernet => Config::new(ethernet_addr.into()),
@@ -49,12 +48,12 @@ fn main() {
     let mut iface = Interface::new(config, &mut device, Instant::now());
     iface.update_ip_addrs(|ip_addrs| {
         ip_addrs
-            .push(IpCidr::new(IpAddress::from(local_addr), 64))
+            .push(IpCidr::new(IpAddress::from(LOCAL_ADDR), 64))
             .unwrap();
     });
     iface
         .routes_mut()
-        .add_default_ipv6_route(Ipv6Address::from_parts(&ROUTER_ADDR))
+        .add_default_ipv6_route(ROUTER_ADDR)
         .unwrap();
 
     // Create sockets
@@ -65,9 +64,7 @@ fn main() {
     let udp_handle = sockets.add(udp_socket);
 
     // Join a multicast group
-    iface
-        .join_multicast_group(Ipv6Address::from_parts(&GROUP))
-        .unwrap();
+    iface.join_multicast_group(GROUP).unwrap();
 
     loop {
         let timestamp = Instant::now();

+ 5 - 5
src/iface/fragmentation.rs

@@ -137,7 +137,7 @@ impl<K> PacketAssembler<K> {
     /// # Errors
     ///
     /// - Returns [`Error::PacketAssemblerBufferTooSmall`] when trying to add data into the buffer at a non-existing
-    /// place.
+    ///   place.
     pub(crate) fn add(&mut self, data: &[u8], offset: usize) -> Result<(), AssemblerError> {
         #[cfg(not(feature = "alloc"))]
         if self.buffer.len() < offset + data.len() {
@@ -329,8 +329,8 @@ impl Fragmenter {
             #[cfg(feature = "proto-ipv4-fragmentation")]
             ipv4: Ipv4Fragmenter {
                 repr: Ipv4Repr {
-                    src_addr: Ipv4Address::default(),
-                    dst_addr: Ipv4Address::default(),
+                    src_addr: Ipv4Address::new(0, 0, 0, 0),
+                    dst_addr: Ipv4Address::new(0, 0, 0, 0),
                     next_header: IpProtocol::Unknown(0),
                     payload_len: 0,
                     hop_limit: 0,
@@ -373,8 +373,8 @@ impl Fragmenter {
         #[cfg(feature = "proto-ipv4-fragmentation")]
         {
             self.ipv4.repr = Ipv4Repr {
-                src_addr: Ipv4Address::default(),
-                dst_addr: Ipv4Address::default(),
+                src_addr: Ipv4Address::new(0, 0, 0, 0),
+                dst_addr: Ipv4Address::new(0, 0, 0, 0),
                 next_header: IpProtocol::Unknown(0),
                 payload_len: 0,
                 hop_limit: 0,

+ 3 - 3
src/iface/interface/ipv4.rs

@@ -70,7 +70,7 @@ impl InterfaceInner {
 
     /// Checks if an ipv4 address is unicast, taking into account subnet broadcast addresses
     fn is_unicast_v4(&self, address: Ipv4Address) -> bool {
-        address.is_unicast() && !self.is_broadcast_v4(address)
+        address.x_is_unicast() && !self.is_broadcast_v4(address)
     }
 
     /// Get the first IPv4 address of the interface.
@@ -182,7 +182,7 @@ impl InterfaceInner {
             // Ignore IP packets not directed at us, or broadcast, or any of the multicast groups.
             // If AnyIP is enabled, also check if the packet is routed locally.
             if !self.any_ip
-                || !ipv4_repr.dst_addr.is_unicast()
+                || !ipv4_repr.dst_addr.x_is_unicast()
                 || self
                     .routes
                     .lookup(&IpAddress::Ipv4(ipv4_repr.dst_addr), self.now)
@@ -260,7 +260,7 @@ impl InterfaceInner {
                 }
 
                 // Discard packets with non-unicast source addresses.
-                if !source_protocol_addr.is_unicast() || !source_hardware_addr.is_unicast() {
+                if !source_protocol_addr.x_is_unicast() || !source_hardware_addr.is_unicast() {
                     net_debug!("arp: non-unicast source address");
                     return None;
                 }

+ 19 - 18
src/iface/interface/ipv6.rs

@@ -37,9 +37,9 @@ impl InterfaceInner {
             }
 
             if dst_addr.is_multicast()
-                && matches!(dst_addr.multicast_scope(), Ipv6MulticastScope::LinkLocal)
+                && matches!(dst_addr.x_multicast_scope(), Ipv6MulticastScope::LinkLocal)
                 && src_addr.is_multicast()
-                && !matches!(src_addr.multicast_scope(), Ipv6MulticastScope::LinkLocal)
+                && !matches!(src_addr.x_multicast_scope(), Ipv6MulticastScope::LinkLocal)
             {
                 return false;
             }
@@ -58,7 +58,7 @@ impl InterfaceInner {
         fn common_prefix_length(dst_addr: &Ipv6Cidr, src_addr: &Ipv6Address) -> usize {
             let addr = dst_addr.address();
             let mut bits = 0;
-            for (l, r) in addr.as_bytes().iter().zip(src_addr.as_bytes().iter()) {
+            for (l, r) in addr.octets().iter().zip(src_addr.octets().iter()) {
                 if l == r {
                     bits += 8;
                 } else {
@@ -82,7 +82,7 @@ impl InterfaceInner {
                 .count()
                 == 0
         {
-            return Ipv6Address::LOOPBACK;
+            return Ipv6Address::LOCALHOST;
         }
 
         let mut candidate = self
@@ -111,15 +111,16 @@ impl InterfaceInner {
             }
 
             // Rule 2: prefer appropriate scope.
-            if (candidate.address().multicast_scope() as u8)
-                < (addr.address().multicast_scope() as u8)
+            if (candidate.address().x_multicast_scope() as u8)
+                < (addr.address().x_multicast_scope() as u8)
             {
-                if (candidate.address().multicast_scope() as u8)
-                    < (dst_addr.multicast_scope() as u8)
+                if (candidate.address().x_multicast_scope() as u8)
+                    < (dst_addr.x_multicast_scope() as u8)
                 {
                     candidate = addr;
                 }
-            } else if (addr.address().multicast_scope() as u8) > (dst_addr.multicast_scope() as u8)
+            } else if (addr.address().x_multicast_scope() as u8)
+                > (dst_addr.x_multicast_scope() as u8)
             {
                 candidate = addr;
             }
@@ -147,10 +148,10 @@ impl InterfaceInner {
     pub fn has_solicited_node(&self, addr: Ipv6Address) -> bool {
         self.ip_addrs.iter().any(|cidr| {
             match *cidr {
-                IpCidr::Ipv6(cidr) if cidr.address() != Ipv6Address::LOOPBACK => {
+                IpCidr::Ipv6(cidr) if cidr.address() != Ipv6Address::LOCALHOST => {
                     // Take the lower order 24 bits of the IPv6 address and
                     // append those bits to FF02:0:0:0:0:1:FF00::/104.
-                    addr.as_bytes()[14..] == cidr.address().as_bytes()[14..]
+                    addr.octets()[14..] == cidr.address().octets()[14..]
                 }
                 _ => false,
             }
@@ -192,7 +193,7 @@ impl InterfaceInner {
     ) -> Option<Packet<'frame>> {
         let ipv6_repr = check!(Ipv6Repr::parse(ipv6_packet));
 
-        if !ipv6_repr.src_addr.is_unicast() {
+        if !ipv6_repr.src_addr.x_is_unicast() {
             // Discard packets with non-unicast source addresses.
             net_debug!("non-unicast source address");
             return None;
@@ -213,7 +214,7 @@ impl InterfaceInner {
         {
             // If AnyIP is enabled, also check if the packet is routed locally.
             if !self.any_ip
-                || !ipv6_repr.dst_addr.is_unicast()
+                || !ipv6_repr.dst_addr.x_is_unicast()
                 || self
                     .routes
                     .lookup(&IpAddress::Ipv6(ipv6_repr.dst_addr), self.now)
@@ -230,7 +231,7 @@ impl InterfaceInner {
         let handled_by_raw_socket = false;
 
         #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
-        if ipv6_repr.dst_addr.is_unicast() {
+        if ipv6_repr.dst_addr.x_is_unicast() {
             self.neighbor_cache.reset_expiry_if_existing(
                 IpAddress::Ipv6(ipv6_repr.src_addr),
                 source_hardware_addr,
@@ -436,7 +437,7 @@ impl InterfaceInner {
                 let ip_addr = ip_repr.src_addr.into();
                 if let Some(lladdr) = lladdr {
                     let lladdr = check!(lladdr.parse(self.caps.medium));
-                    if !lladdr.is_unicast() || !target_addr.is_unicast() {
+                    if !lladdr.is_unicast() || !target_addr.x_is_unicast() {
                         return None;
                     }
                     if flags.contains(NdiscNeighborFlags::OVERRIDE)
@@ -454,7 +455,7 @@ impl InterfaceInner {
             } => {
                 if let Some(lladdr) = lladdr {
                     let lladdr = check!(lladdr.parse(self.caps.medium));
-                    if !lladdr.is_unicast() || !target_addr.is_unicast() {
+                    if !lladdr.is_unicast() || !target_addr.x_is_unicast() {
                         return None;
                     }
                     self.neighbor_cache
@@ -492,7 +493,7 @@ impl InterfaceInner {
         let src_addr = ipv6_repr.dst_addr;
         let dst_addr = ipv6_repr.src_addr;
 
-        let src_addr = if src_addr.is_unicast() {
+        let src_addr = if src_addr.x_is_unicast() {
             src_addr
         } else {
             self.get_source_address_ipv6(&dst_addr)
@@ -524,7 +525,7 @@ impl InterfaceInner {
 
         // Per [RFC 3810 § 5.2.14], all MLDv2 reports are sent to ff02::16.
         // [RFC 3810 § 5.2.14]: https://tools.ietf.org/html/rfc3810#section-5.2.14
-        let dst_addr = Ipv6Address::LINK_LOCAL_ALL_MLDV2_ROUTERS;
+        let dst_addr = IPV6_LINK_LOCAL_ALL_MLDV2_ROUTERS;
 
         // Create a dummy IPv6 extension header so we can calculate the total length of the packet.
         // The actual extension header will be created later by Packet::emit_payload().

+ 24 - 19
src/iface/interface/mod.rs

@@ -830,12 +830,12 @@ impl InterfaceInner {
 
         match addr {
             #[cfg(feature = "proto-ipv4")]
-            IpAddress::Ipv4(key) => key == Ipv4Address::MULTICAST_ALL_SYSTEMS,
+            IpAddress::Ipv4(key) => key == IPV4_MULTICAST_ALL_SYSTEMS,
             #[cfg(feature = "proto-rpl")]
-            IpAddress::Ipv6(Ipv6Address::LINK_LOCAL_ALL_RPL_NODES) => true,
+            IpAddress::Ipv6(IPV6_LINK_LOCAL_ALL_RPL_NODES) => true,
             #[cfg(feature = "proto-ipv6")]
             IpAddress::Ipv6(key) => {
-                key == Ipv6Address::LINK_LOCAL_ALL_NODES || self.has_solicited_node(key)
+                key == IPV6_LINK_LOCAL_ALL_NODES || self.has_solicited_node(key)
             }
             #[allow(unreachable_patterns)]
             _ => false,
@@ -987,30 +987,35 @@ impl InterfaceInner {
         }
 
         if dst_addr.is_multicast() {
-            let b = dst_addr.as_bytes();
             let hardware_addr = match *dst_addr {
                 #[cfg(feature = "proto-ipv4")]
-                IpAddress::Ipv4(_addr) => match self.caps.medium {
+                IpAddress::Ipv4(addr) => match self.caps.medium {
                     #[cfg(feature = "medium-ethernet")]
-                    Medium::Ethernet => HardwareAddress::Ethernet(EthernetAddress::from_bytes(&[
-                        0x01,
-                        0x00,
-                        0x5e,
-                        b[1] & 0x7F,
-                        b[2],
-                        b[3],
-                    ])),
+                    Medium::Ethernet => {
+                        let b = addr.octets();
+                        HardwareAddress::Ethernet(EthernetAddress::from_bytes(&[
+                            0x01,
+                            0x00,
+                            0x5e,
+                            b[1] & 0x7F,
+                            b[2],
+                            b[3],
+                        ]))
+                    }
                     #[cfg(feature = "medium-ieee802154")]
                     Medium::Ieee802154 => unreachable!(),
                     #[cfg(feature = "medium-ip")]
                     Medium::Ip => unreachable!(),
                 },
                 #[cfg(feature = "proto-ipv6")]
-                IpAddress::Ipv6(_addr) => match self.caps.medium {
+                IpAddress::Ipv6(addr) => match self.caps.medium {
                     #[cfg(feature = "medium-ethernet")]
-                    Medium::Ethernet => HardwareAddress::Ethernet(EthernetAddress::from_bytes(&[
-                        0x33, 0x33, b[12], b[13], b[14], b[15],
-                    ])),
+                    Medium::Ethernet => {
+                        let b = addr.octets();
+                        HardwareAddress::Ethernet(EthernetAddress::from_bytes(&[
+                            0x33, 0x33, b[12], b[13], b[14], b[15],
+                        ]))
+                    }
                     #[cfg(feature = "medium-ieee802154")]
                     Medium::Ieee802154 => {
                         // Not sure if this is correct
@@ -1183,8 +1188,8 @@ impl InterfaceInner {
         };
 
         // Emit function for the IP header and payload.
-        let emit_ip = |repr: &IpRepr, mut tx_buffer: &mut [u8]| {
-            repr.emit(&mut tx_buffer, &self.caps.checksum);
+        let emit_ip = |repr: &IpRepr, tx_buffer: &mut [u8]| {
+            repr.emit(&mut *tx_buffer, &self.caps.checksum);
 
             let payload = &mut tx_buffer[repr.header_len()..];
             packet.emit_payload(repr, payload, &caps)

+ 2 - 4
src/iface/interface/multicast.rs

@@ -334,9 +334,7 @@ impl InterfaceInner {
                 max_resp_time,
             } => {
                 // General query
-                if group_addr.is_unspecified()
-                    && ipv4_repr.dst_addr == Ipv4Address::MULTICAST_ALL_SYSTEMS
-                {
+                if group_addr.is_unspecified() && ipv4_repr.dst_addr == IPV4_MULTICAST_ALL_SYSTEMS {
                     let ipv4_multicast_group_count = self
                         .multicast
                         .groups
@@ -418,7 +416,7 @@ impl InterfaceInner {
             Packet::new_ipv4(
                 Ipv4Repr {
                     src_addr: iface_addr,
-                    dst_addr: Ipv4Address::MULTICAST_ALL_ROUTERS,
+                    dst_addr: IPV4_MULTICAST_ALL_ROUTERS,
                     next_header: IpProtocol::Igmp,
                     payload_len: igmp_repr.buffer_len(),
                     hop_limit: 1,

+ 2 - 1
src/iface/interface/sixlowpan.rs

@@ -557,7 +557,8 @@ impl InterfaceInner {
     ///  - total size: the size of a compressed IPv6 packet
     ///  - compressed header size: the size of the compressed headers
     ///  - uncompressed header size: the size of the headers that are not compressed
-    ///  They are returned as a tuple in the same order.
+    ///
+    /// They are returned as a tuple in the same order.
     fn compressed_packet_size(
         packet: &PacketV6,
         ieee_repr: &Ieee802154Repr,

+ 57 - 49
src/iface/interface/tests/ipv4.rs

@@ -72,7 +72,7 @@ fn test_no_icmp_no_unicast(#[case] medium: Medium) {
     // this should not trigger and Destination Unreachable
     // response. See RFC 1122 § 3.2.2.
     let repr = IpRepr::Ipv4(Ipv4Repr {
-        src_addr: Ipv4Address([0x7f, 0x00, 0x00, 0x01]),
+        src_addr: Ipv4Address::new(0x7f, 0x00, 0x00, 0x01),
         dst_addr: Ipv4Address::BROADCAST,
         next_header: IpProtocol::Unknown(0x0c),
         payload_len: 0,
@@ -110,8 +110,8 @@ fn test_icmp_error_no_payload(#[case] medium: Medium) {
 
     // Unknown Ipv4 Protocol with no payload
     let repr = IpRepr::Ipv4(Ipv4Repr {
-        src_addr: Ipv4Address([0x7f, 0x00, 0x00, 0x02]),
-        dst_addr: Ipv4Address([0x7f, 0x00, 0x00, 0x01]),
+        src_addr: Ipv4Address::new(0x7f, 0x00, 0x00, 0x02),
+        dst_addr: Ipv4Address::new(0x7f, 0x00, 0x00, 0x01),
         next_header: IpProtocol::Unknown(0x0c),
         payload_len: 0,
         hop_limit: 0x40,
@@ -126,8 +126,8 @@ fn test_icmp_error_no_payload(#[case] medium: Medium) {
     let icmp_repr = Icmpv4Repr::DstUnreachable {
         reason: Icmpv4DstUnreachable::ProtoUnreachable,
         header: Ipv4Repr {
-            src_addr: Ipv4Address([0x7f, 0x00, 0x00, 0x02]),
-            dst_addr: Ipv4Address([0x7f, 0x00, 0x00, 0x01]),
+            src_addr: Ipv4Address::new(0x7f, 0x00, 0x00, 0x02),
+            dst_addr: Ipv4Address::new(0x7f, 0x00, 0x00, 0x01),
             next_header: IpProtocol::Unknown(12),
             payload_len: 0,
             hop_limit: 64,
@@ -137,8 +137,8 @@ fn test_icmp_error_no_payload(#[case] medium: Medium) {
 
     let expected_repr = Packet::new_ipv4(
         Ipv4Repr {
-            src_addr: Ipv4Address([0x7f, 0x00, 0x00, 0x01]),
-            dst_addr: Ipv4Address([0x7f, 0x00, 0x00, 0x02]),
+            src_addr: Ipv4Address::new(0x7f, 0x00, 0x00, 0x01),
+            dst_addr: Ipv4Address::new(0x7f, 0x00, 0x00, 0x02),
             next_header: IpProtocol::Icmp,
             payload_len: icmp_repr.buffer_len(),
             hop_limit: 64,
@@ -170,62 +170,70 @@ fn test_local_subnet_broadcasts(#[case] medium: Medium) {
     let (mut iface, _, _device) = setup(medium);
     iface.update_ip_addrs(|addrs| {
         addrs.iter_mut().next().map(|addr| {
-            *addr = IpCidr::Ipv4(Ipv4Cidr::new(Ipv4Address([192, 168, 1, 23]), 24));
+            *addr = IpCidr::Ipv4(Ipv4Cidr::new(Ipv4Address::new(192, 168, 1, 23), 24));
         });
     });
 
     assert!(iface
         .inner
-        .is_broadcast_v4(Ipv4Address([255, 255, 255, 255])));
+        .is_broadcast_v4(Ipv4Address::new(255, 255, 255, 255)));
     assert!(!iface
         .inner
-        .is_broadcast_v4(Ipv4Address([255, 255, 255, 254])));
-    assert!(iface.inner.is_broadcast_v4(Ipv4Address([192, 168, 1, 255])));
-    assert!(!iface.inner.is_broadcast_v4(Ipv4Address([192, 168, 1, 254])));
+        .is_broadcast_v4(Ipv4Address::new(255, 255, 255, 254)));
+    assert!(iface
+        .inner
+        .is_broadcast_v4(Ipv4Address::new(192, 168, 1, 255)));
+    assert!(!iface
+        .inner
+        .is_broadcast_v4(Ipv4Address::new(192, 168, 1, 254)));
 
     iface.update_ip_addrs(|addrs| {
         addrs.iter_mut().next().map(|addr| {
-            *addr = IpCidr::Ipv4(Ipv4Cidr::new(Ipv4Address([192, 168, 23, 24]), 16));
+            *addr = IpCidr::Ipv4(Ipv4Cidr::new(Ipv4Address::new(192, 168, 23, 24), 16));
         });
     });
     assert!(iface
         .inner
-        .is_broadcast_v4(Ipv4Address([255, 255, 255, 255])));
+        .is_broadcast_v4(Ipv4Address::new(255, 255, 255, 255)));
     assert!(!iface
         .inner
-        .is_broadcast_v4(Ipv4Address([255, 255, 255, 254])));
+        .is_broadcast_v4(Ipv4Address::new(255, 255, 255, 254)));
     assert!(!iface
         .inner
-        .is_broadcast_v4(Ipv4Address([192, 168, 23, 255])));
+        .is_broadcast_v4(Ipv4Address::new(192, 168, 23, 255)));
     assert!(!iface
         .inner
-        .is_broadcast_v4(Ipv4Address([192, 168, 23, 254])));
+        .is_broadcast_v4(Ipv4Address::new(192, 168, 23, 254)));
     assert!(!iface
         .inner
-        .is_broadcast_v4(Ipv4Address([192, 168, 255, 254])));
+        .is_broadcast_v4(Ipv4Address::new(192, 168, 255, 254)));
     assert!(iface
         .inner
-        .is_broadcast_v4(Ipv4Address([192, 168, 255, 255])));
+        .is_broadcast_v4(Ipv4Address::new(192, 168, 255, 255)));
 
     iface.update_ip_addrs(|addrs| {
         addrs.iter_mut().next().map(|addr| {
-            *addr = IpCidr::Ipv4(Ipv4Cidr::new(Ipv4Address([192, 168, 23, 24]), 8));
+            *addr = IpCidr::Ipv4(Ipv4Cidr::new(Ipv4Address::new(192, 168, 23, 24), 8));
         });
     });
     assert!(iface
         .inner
-        .is_broadcast_v4(Ipv4Address([255, 255, 255, 255])));
+        .is_broadcast_v4(Ipv4Address::new(255, 255, 255, 255)));
     assert!(!iface
         .inner
-        .is_broadcast_v4(Ipv4Address([255, 255, 255, 254])));
-    assert!(!iface.inner.is_broadcast_v4(Ipv4Address([192, 23, 1, 255])));
-    assert!(!iface.inner.is_broadcast_v4(Ipv4Address([192, 23, 1, 254])));
+        .is_broadcast_v4(Ipv4Address::new(255, 255, 255, 254)));
     assert!(!iface
         .inner
-        .is_broadcast_v4(Ipv4Address([192, 255, 255, 254])));
+        .is_broadcast_v4(Ipv4Address::new(192, 23, 1, 255)));
+    assert!(!iface
+        .inner
+        .is_broadcast_v4(Ipv4Address::new(192, 23, 1, 254)));
+    assert!(!iface
+        .inner
+        .is_broadcast_v4(Ipv4Address::new(192, 255, 255, 254)));
     assert!(iface
         .inner
-        .is_broadcast_v4(Ipv4Address([192, 255, 255, 255])));
+        .is_broadcast_v4(Ipv4Address::new(192, 255, 255, 255)));
 }
 
 #[rstest]
@@ -250,8 +258,8 @@ fn test_icmp_error_port_unreachable(#[case] medium: Medium) {
     };
 
     let ip_repr = IpRepr::Ipv4(Ipv4Repr {
-        src_addr: Ipv4Address([0x7f, 0x00, 0x00, 0x02]),
-        dst_addr: Ipv4Address([0x7f, 0x00, 0x00, 0x01]),
+        src_addr: Ipv4Address::new(0x7f, 0x00, 0x00, 0x02),
+        dst_addr: Ipv4Address::new(0x7f, 0x00, 0x00, 0x01),
         next_header: IpProtocol::Udp,
         payload_len: udp_repr.header_len() + UDP_PAYLOAD.len(),
         hop_limit: 64,
@@ -274,8 +282,8 @@ fn test_icmp_error_port_unreachable(#[case] medium: Medium) {
     let icmp_repr = Icmpv4Repr::DstUnreachable {
         reason: Icmpv4DstUnreachable::PortUnreachable,
         header: Ipv4Repr {
-            src_addr: Ipv4Address([0x7f, 0x00, 0x00, 0x02]),
-            dst_addr: Ipv4Address([0x7f, 0x00, 0x00, 0x01]),
+            src_addr: Ipv4Address::new(0x7f, 0x00, 0x00, 0x02),
+            dst_addr: Ipv4Address::new(0x7f, 0x00, 0x00, 0x01),
             next_header: IpProtocol::Udp,
             payload_len: udp_repr.header_len() + UDP_PAYLOAD.len(),
             hop_limit: 64,
@@ -284,8 +292,8 @@ fn test_icmp_error_port_unreachable(#[case] medium: Medium) {
     };
     let expected_repr = Packet::new_ipv4(
         Ipv4Repr {
-            src_addr: Ipv4Address([0x7f, 0x00, 0x00, 0x01]),
-            dst_addr: Ipv4Address([0x7f, 0x00, 0x00, 0x02]),
+            src_addr: Ipv4Address::new(0x7f, 0x00, 0x00, 0x01),
+            dst_addr: Ipv4Address::new(0x7f, 0x00, 0x00, 0x02),
             next_header: IpProtocol::Icmp,
             payload_len: icmp_repr.buffer_len(),
             hop_limit: 64,
@@ -303,7 +311,7 @@ fn test_icmp_error_port_unreachable(#[case] medium: Medium) {
     );
 
     let ip_repr = IpRepr::Ipv4(Ipv4Repr {
-        src_addr: Ipv4Address([0x7f, 0x00, 0x00, 0x02]),
+        src_addr: Ipv4Address::new(0x7f, 0x00, 0x00, 0x02),
         dst_addr: Ipv4Address::BROADCAST,
         next_header: IpProtocol::Udp,
         payload_len: udp_repr.header_len() + UDP_PAYLOAD.len(),
@@ -346,7 +354,7 @@ fn test_handle_ipv4_broadcast(#[case] medium: Medium) {
     let (mut iface, mut sockets, _device) = setup(medium);
 
     let our_ipv4_addr = iface.ipv4_addr().unwrap();
-    let src_ipv4_addr = Ipv4Address([127, 0, 0, 2]);
+    let src_ipv4_addr = Ipv4Address::new(127, 0, 0, 2);
 
     // ICMPv4 echo request
     let icmpv4_data: [u8; 4] = [0xaa, 0x00, 0x00, 0xff];
@@ -415,8 +423,8 @@ fn test_handle_valid_arp_request(#[case] medium: Medium) {
 
     let mut eth_bytes = vec![0u8; 42];
 
-    let local_ip_addr = Ipv4Address([0x7f, 0x00, 0x00, 0x01]);
-    let remote_ip_addr = Ipv4Address([0x7f, 0x00, 0x00, 0x02]);
+    let local_ip_addr = Ipv4Address::new(0x7f, 0x00, 0x00, 0x01);
+    let remote_ip_addr = Ipv4Address::new(0x7f, 0x00, 0x00, 0x02);
     let local_hw_addr = EthernetAddress([0x02, 0x02, 0x02, 0x02, 0x02, 0x02]);
     let remote_hw_addr = EthernetAddress([0x52, 0x54, 0x00, 0x00, 0x00, 0x00]);
 
@@ -471,7 +479,7 @@ fn test_handle_other_arp_request(#[case] medium: Medium) {
 
     let mut eth_bytes = vec![0u8; 42];
 
-    let remote_ip_addr = Ipv4Address([0x7f, 0x00, 0x00, 0x02]);
+    let remote_ip_addr = Ipv4Address::new(0x7f, 0x00, 0x00, 0x02);
     let remote_hw_addr = EthernetAddress([0x52, 0x54, 0x00, 0x00, 0x00, 0x00]);
 
     let repr = ArpRepr::EthernetIpv4 {
@@ -479,7 +487,7 @@ fn test_handle_other_arp_request(#[case] medium: Medium) {
         source_hardware_addr: remote_hw_addr,
         source_protocol_addr: remote_ip_addr,
         target_hardware_addr: EthernetAddress::default(),
-        target_protocol_addr: Ipv4Address([0x7f, 0x00, 0x00, 0x03]),
+        target_protocol_addr: Ipv4Address::new(0x7f, 0x00, 0x00, 0x03),
     };
 
     let mut frame = EthernetFrame::new_unchecked(&mut eth_bytes);
@@ -519,8 +527,8 @@ fn test_arp_flush_after_update_ip(#[case] medium: Medium) {
 
     let mut eth_bytes = vec![0u8; 42];
 
-    let local_ip_addr = Ipv4Address([0x7f, 0x00, 0x00, 0x01]);
-    let remote_ip_addr = Ipv4Address([0x7f, 0x00, 0x00, 0x02]);
+    let local_ip_addr = Ipv4Address::new(0x7f, 0x00, 0x00, 0x01);
+    let remote_ip_addr = Ipv4Address::new(0x7f, 0x00, 0x00, 0x02);
     let local_hw_addr = EthernetAddress([0x02, 0x02, 0x02, 0x02, 0x02, 0x02]);
     let remote_hw_addr = EthernetAddress([0x52, 0x54, 0x00, 0x00, 0x00, 0x00]);
 
@@ -529,7 +537,7 @@ fn test_arp_flush_after_update_ip(#[case] medium: Medium) {
         source_hardware_addr: remote_hw_addr,
         source_protocol_addr: remote_ip_addr,
         target_hardware_addr: EthernetAddress::default(),
-        target_protocol_addr: Ipv4Address([0x7f, 0x00, 0x00, 0x01]),
+        target_protocol_addr: Ipv4Address::new(0x7f, 0x00, 0x00, 0x01),
     };
 
     let mut frame = EthernetFrame::new_unchecked(&mut eth_bytes);
@@ -569,7 +577,7 @@ fn test_arp_flush_after_update_ip(#[case] medium: Medium) {
     );
 
     // Update IP addrs to trigger ARP cache flush
-    let local_ip_addr_new = Ipv4Address([0x7f, 0x00, 0x00, 0x01]);
+    let local_ip_addr_new = Ipv4Address::new(0x7f, 0x00, 0x00, 0x01);
     iface.update_ip_addrs(|addrs| {
         addrs.iter_mut().next().map(|addr| {
             *addr = IpCidr::Ipv4(Ipv4Cidr::new(local_ip_addr_new, 24));
@@ -746,7 +754,7 @@ fn test_handle_igmp(#[case] medium: Medium) {
     assert_eq!(leaves.len(), 2);
     for (i, group_addr) in groups.iter().cloned().enumerate() {
         assert_eq!(leaves[i].0.next_header, IpProtocol::Igmp);
-        assert_eq!(leaves[i].0.dst_addr, Ipv4Address::MULTICAST_ALL_ROUTERS);
+        assert_eq!(leaves[i].0.dst_addr, IPV4_MULTICAST_ALL_ROUTERS);
         assert_eq!(leaves[i].1, IgmpRepr::LeaveGroup { group_addr });
     }
 }
@@ -771,8 +779,8 @@ fn test_raw_socket_no_reply(#[case] medium: Medium) {
     let raw_socket = raw::Socket::new(IpVersion::Ipv4, IpProtocol::Udp, rx_buffer, tx_buffer);
     sockets.add(raw_socket);
 
-    let src_addr = Ipv4Address([127, 0, 0, 2]);
-    let dst_addr = Ipv4Address([127, 0, 0, 1]);
+    let src_addr = Ipv4Address::new(127, 0, 0, 2);
+    let dst_addr = Ipv4Address::new(127, 0, 0, 1);
 
     const PAYLOAD_LEN: usize = 10;
 
@@ -871,8 +879,8 @@ fn test_raw_socket_with_udp_socket(#[case] medium: Medium) {
     );
     sockets.add(raw_socket);
 
-    let src_addr = Ipv4Address([127, 0, 0, 2]);
-    let dst_addr = Ipv4Address([127, 0, 0, 1]);
+    let src_addr = Ipv4Address::new(127, 0, 0, 2);
+    let dst_addr = Ipv4Address::new(127, 0, 0, 1);
 
     let udp_repr = UdpRepr {
         src_port: 67,
@@ -951,8 +959,8 @@ fn test_icmp_reply_size(#[case] medium: Medium) {
 
     let (mut iface, mut sockets, _device) = setup(medium);
 
-    let src_addr = Ipv4Address([192, 168, 1, 1]);
-    let dst_addr = Ipv4Address([192, 168, 1, 2]);
+    let src_addr = Ipv4Address::new(192, 168, 1, 1);
+    let dst_addr = Ipv4Address::new(192, 168, 1, 2);
 
     // UDP packet that if not tructated will cause a icmp port unreachable reply
     // to exceed the minimum mtu bytes in length.

+ 65 - 67
src/iface/interface/tests/ipv6.rs

@@ -49,8 +49,8 @@ fn any_ip(#[case] medium: Medium) {
         parse_ipv6(&data),
         Ok(Packet::new_ipv6(
             Ipv6Repr {
-                src_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002]),
-                dst_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0003]),
+                src_addr: Ipv6Address::new(0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002),
+                dst_addr: Ipv6Address::new(0xfdbe, 0, 0, 0, 0, 0, 0, 0x0003),
                 hop_limit: 64,
                 next_header: IpProtocol::Icmpv6,
                 payload_len: 8,
@@ -73,9 +73,7 @@ fn any_ip(#[case] medium: Medium) {
                     Ipv6Address::new(0xfdbe, 0, 0, 0, 0, 0, 0, 0),
                     64,
                 )),
-                via_router: IpAddress::Ipv6(Ipv6Address::from_parts(&[
-                    0xfdbe, 0, 0, 0, 0, 0, 0, 0x0001,
-                ])),
+                via_router: IpAddress::Ipv6(Ipv6Address::new(0xfdbe, 0, 0, 0, 0, 0, 0, 0x0001)),
                 preferred_until: None,
                 expires_at: None,
             })
@@ -157,8 +155,8 @@ fn hop_by_hop_skip_with_icmp(#[case] medium: Medium) {
 
     let response = Some(Packet::new_ipv6(
         Ipv6Repr {
-            src_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0001]),
-            dst_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002]),
+            src_addr: Ipv6Address::new(0xfdbe, 0, 0, 0, 0, 0, 0, 0x0001),
+            dst_addr: Ipv6Address::new(0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002),
             hop_limit: 64,
             next_header: IpProtocol::Icmpv6,
             payload_len: 19,
@@ -350,8 +348,8 @@ fn imcp_empty_echo_request(#[case] medium: Medium) {
         parse_ipv6(&data),
         Ok(Packet::new_ipv6(
             Ipv6Repr {
-                src_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002]),
-                dst_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0001]),
+                src_addr: Ipv6Address::new(0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002),
+                dst_addr: Ipv6Address::new(0xfdbe, 0, 0, 0, 0, 0, 0, 0x0001),
                 hop_limit: 64,
                 next_header: IpProtocol::Icmpv6,
                 payload_len: 8,
@@ -366,8 +364,8 @@ fn imcp_empty_echo_request(#[case] medium: Medium) {
 
     let response = Some(Packet::new_ipv6(
         Ipv6Repr {
-            src_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0001]),
-            dst_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002]),
+            src_addr: Ipv6Address::new(0xfdbe, 0, 0, 0, 0, 0, 0, 0x0001),
+            dst_addr: Ipv6Address::new(0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002),
             hop_limit: 64,
             next_header: IpProtocol::Icmpv6,
             payload_len: 8,
@@ -411,8 +409,8 @@ fn icmp_echo_request(#[case] medium: Medium) {
         parse_ipv6(&data),
         Ok(Packet::new_ipv6(
             Ipv6Repr {
-                src_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002]),
-                dst_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0001]),
+                src_addr: Ipv6Address::new(0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002),
+                dst_addr: Ipv6Address::new(0xfdbe, 0, 0, 0, 0, 0, 0, 0x0001),
                 hop_limit: 64,
                 next_header: IpProtocol::Icmpv6,
                 payload_len: 19,
@@ -427,8 +425,8 @@ fn icmp_echo_request(#[case] medium: Medium) {
 
     let response = Some(Packet::new_ipv6(
         Ipv6Repr {
-            src_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0001]),
-            dst_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002]),
+            src_addr: Ipv6Address::new(0xfdbe, 0, 0, 0, 0, 0, 0, 0x0001),
+            dst_addr: Ipv6Address::new(0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002),
             hop_limit: 64,
             next_header: IpProtocol::Icmpv6,
             payload_len: 19,
@@ -472,8 +470,8 @@ fn icmp_echo_reply_as_input(#[case] medium: Medium) {
         parse_ipv6(&data),
         Ok(Packet::new_ipv6(
             Ipv6Repr {
-                src_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002]),
-                dst_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0001]),
+                src_addr: Ipv6Address::new(0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002),
+                dst_addr: Ipv6Address::new(0xfdbe, 0, 0, 0, 0, 0, 0, 0x0001),
                 hop_limit: 64,
                 next_header: IpProtocol::Icmpv6,
                 payload_len: 19,
@@ -517,8 +515,8 @@ fn unknown_proto_with_multicast_dst_address(#[case] medium: Medium) {
 
     let response = Some(Packet::new_ipv6(
         Ipv6Repr {
-            src_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0001]),
-            dst_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002]),
+            src_addr: Ipv6Address::new(0xfdbe, 0, 0, 0, 0, 0, 0, 0x0001),
+            dst_addr: Ipv6Address::new(0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002),
             hop_limit: 64,
             next_header: IpProtocol::Icmpv6,
             payload_len: 48,
@@ -527,8 +525,8 @@ fn unknown_proto_with_multicast_dst_address(#[case] medium: Medium) {
             reason: Icmpv6ParamProblem::UnrecognizedNxtHdr,
             pointer: 40,
             header: Ipv6Repr {
-                src_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002]),
-                dst_addr: Ipv6Address::from_parts(&[0xff02, 0, 0, 0, 0, 0, 0, 0x0001]),
+                src_addr: Ipv6Address::new(0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002),
+                dst_addr: Ipv6Address::new(0xff02, 0, 0, 0, 0, 0, 0, 0x0001),
                 hop_limit: 64,
                 next_header: IpProtocol::Unknown(0x0c),
                 payload_len: 0,
@@ -567,8 +565,8 @@ fn unknown_proto(#[case] medium: Medium) {
 
     let response = Some(Packet::new_ipv6(
         Ipv6Repr {
-            src_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0001]),
-            dst_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002]),
+            src_addr: Ipv6Address::new(0xfdbe, 0, 0, 0, 0, 0, 0, 0x0001),
+            dst_addr: Ipv6Address::new(0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002),
             hop_limit: 64,
             next_header: IpProtocol::Icmpv6,
             payload_len: 48,
@@ -577,8 +575,8 @@ fn unknown_proto(#[case] medium: Medium) {
             reason: Icmpv6ParamProblem::UnrecognizedNxtHdr,
             pointer: 40,
             header: Ipv6Repr {
-                src_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002]),
-                dst_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0001]),
+                src_addr: Ipv6Address::new(0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002),
+                dst_addr: Ipv6Address::new(0xfdbe, 0, 0, 0, 0, 0, 0, 0x0001),
                 hop_limit: 64,
                 next_header: IpProtocol::Unknown(0x0c),
                 payload_len: 0,
@@ -616,15 +614,15 @@ fn ndsic_neighbor_advertisement_ethernet(#[case] medium: Medium) {
         parse_ipv6(&data),
         Ok(Packet::new_ipv6(
             Ipv6Repr {
-                src_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002]),
-                dst_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0001]),
+                src_addr: Ipv6Address::new(0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002),
+                dst_addr: Ipv6Address::new(0xfdbe, 0, 0, 0, 0, 0, 0, 0x0001),
                 hop_limit: 255,
                 next_header: IpProtocol::Icmpv6,
                 payload_len: 32,
             },
             IpPayload::Icmpv6(Icmpv6Repr::Ndisc(NdiscRepr::NeighborAdvert {
                 flags: NdiscNeighborFlags::SOLICITED,
-                target_addr: Ipv6Address::from_parts(&[0xfe80, 0, 0, 0, 0, 0, 0, 0x0002]),
+                target_addr: Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 0x0002),
                 lladdr: Some(RawHardwareAddress::from_bytes(&[0, 0, 0, 0, 0, 1])),
             }))
         ))
@@ -646,7 +644,7 @@ fn ndsic_neighbor_advertisement_ethernet(#[case] medium: Medium) {
 
     assert_eq!(
         iface.inner.neighbor_cache.lookup(
-            &IpAddress::Ipv6(Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002])),
+            &IpAddress::Ipv6(Ipv6Address::new(0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002)),
             iface.inner.now,
         ),
         NeighborAnswer::Found(HardwareAddress::Ethernet(EthernetAddress::from_bytes(&[
@@ -671,15 +669,15 @@ fn ndsic_neighbor_advertisement_ethernet_multicast_addr(#[case] medium: Medium)
         parse_ipv6(&data),
         Ok(Packet::new_ipv6(
             Ipv6Repr {
-                src_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002]),
-                dst_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0001]),
+                src_addr: Ipv6Address::new(0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002),
+                dst_addr: Ipv6Address::new(0xfdbe, 0, 0, 0, 0, 0, 0, 0x0001),
                 hop_limit: 255,
                 next_header: IpProtocol::Icmpv6,
                 payload_len: 32,
             },
             IpPayload::Icmpv6(Icmpv6Repr::Ndisc(NdiscRepr::NeighborAdvert {
                 flags: NdiscNeighborFlags::SOLICITED,
-                target_addr: Ipv6Address::from_parts(&[0xfe80, 0, 0, 0, 0, 0, 0, 0x0002]),
+                target_addr: Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 0x0002),
                 lladdr: Some(RawHardwareAddress::from_bytes(&[
                     0xff, 0xff, 0xff, 0xff, 0xff, 0xff
                 ])),
@@ -703,7 +701,7 @@ fn ndsic_neighbor_advertisement_ethernet_multicast_addr(#[case] medium: Medium)
 
     assert_eq!(
         iface.inner.neighbor_cache.lookup(
-            &IpAddress::Ipv6(Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002])),
+            &IpAddress::Ipv6(Ipv6Address::new(0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002)),
             iface.inner.now,
         ),
         NeighborAnswer::NotFound,
@@ -726,15 +724,15 @@ fn ndsic_neighbor_advertisement_ieee802154(#[case] medium: Medium) {
         parse_ipv6(&data),
         Ok(Packet::new_ipv6(
             Ipv6Repr {
-                src_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002]),
-                dst_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0001]),
+                src_addr: Ipv6Address::new(0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002),
+                dst_addr: Ipv6Address::new(0xfdbe, 0, 0, 0, 0, 0, 0, 0x0001),
                 hop_limit: 255,
                 next_header: IpProtocol::Icmpv6,
                 payload_len: 40,
             },
             IpPayload::Icmpv6(Icmpv6Repr::Ndisc(NdiscRepr::NeighborAdvert {
                 flags: NdiscNeighborFlags::SOLICITED,
-                target_addr: Ipv6Address::from_parts(&[0xfe80, 0, 0, 0, 0, 0, 0, 0x0002]),
+                target_addr: Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 0x0002),
                 lladdr: Some(RawHardwareAddress::from_bytes(&[0, 0, 0, 0, 0, 0, 0, 1])),
             }))
         ))
@@ -756,7 +754,7 @@ fn ndsic_neighbor_advertisement_ieee802154(#[case] medium: Medium) {
 
     assert_eq!(
         iface.inner.neighbor_cache.lookup(
-            &IpAddress::Ipv6(Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002])),
+            &IpAddress::Ipv6(Ipv6Address::new(0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002)),
             iface.inner.now,
         ),
         NeighborAnswer::Found(HardwareAddress::Ieee802154(Ieee802154Address::from_bytes(
@@ -1004,8 +1002,8 @@ fn get_source_address() {
         Ipv6Address::new(0x2001, 0x0db9, 0x0003, 0, 0, 0, 0, 2);
 
     assert_eq!(
-        iface.inner.get_source_address_ipv6(&Ipv6Address::LOOPBACK),
-        Ipv6Address::LOOPBACK
+        iface.inner.get_source_address_ipv6(&Ipv6Address::LOCALHOST),
+        Ipv6Address::LOCALHOST
     );
 
     assert_eq!(
@@ -1027,7 +1025,7 @@ fn get_source_address() {
     assert_eq!(
         iface
             .inner
-            .get_source_address_ipv6(&Ipv6Address::LINK_LOCAL_ALL_NODES),
+            .get_source_address_ipv6(&IPV6_LINK_LOCAL_ALL_NODES),
         OWN_LINK_LOCAL_ADDR
     );
     assert_eq!(
@@ -1056,7 +1054,7 @@ fn get_source_address() {
         OWN_UNIQUE_LOCAL_ADDR1
     );
     assert_eq!(
-        iface.get_source_address_ipv6(&Ipv6Address::LINK_LOCAL_ALL_NODES),
+        iface.get_source_address_ipv6(&IPV6_LINK_LOCAL_ALL_NODES),
         OWN_LINK_LOCAL_ADDR
     );
     assert_eq!(
@@ -1102,8 +1100,8 @@ fn get_source_address_only_link_local() {
         Ipv6Address::new(0x2001, 0x0db9, 0x0003, 0, 0, 0, 0, 2);
 
     assert_eq!(
-        iface.inner.get_source_address_ipv6(&Ipv6Address::LOOPBACK),
-        Ipv6Address::LOOPBACK
+        iface.inner.get_source_address_ipv6(&Ipv6Address::LOCALHOST),
+        Ipv6Address::LOCALHOST
     );
 
     assert_eq!(
@@ -1125,7 +1123,7 @@ fn get_source_address_only_link_local() {
     assert_eq!(
         iface
             .inner
-            .get_source_address_ipv6(&Ipv6Address::LINK_LOCAL_ALL_NODES),
+            .get_source_address_ipv6(&IPV6_LINK_LOCAL_ALL_NODES),
         OWN_LINK_LOCAL_ADDR
     );
     assert_eq!(
@@ -1154,7 +1152,7 @@ fn get_source_address_only_link_local() {
         OWN_LINK_LOCAL_ADDR
     );
     assert_eq!(
-        iface.get_source_address_ipv6(&Ipv6Address::LINK_LOCAL_ALL_NODES),
+        iface.get_source_address_ipv6(&IPV6_LINK_LOCAL_ALL_NODES),
         OWN_LINK_LOCAL_ADDR
     );
     assert_eq!(
@@ -1193,68 +1191,68 @@ fn get_source_address_empty_interface() {
         Ipv6Address::new(0x2001, 0x0db9, 0x0003, 0, 0, 0, 0, 2);
 
     assert_eq!(
-        iface.inner.get_source_address_ipv6(&Ipv6Address::LOOPBACK),
-        Ipv6Address::LOOPBACK
+        iface.inner.get_source_address_ipv6(&Ipv6Address::LOCALHOST),
+        Ipv6Address::LOCALHOST
     );
 
     assert_eq!(
         iface.inner.get_source_address_ipv6(&LINK_LOCAL_ADDR),
-        Ipv6Address::LOOPBACK
+        Ipv6Address::LOCALHOST
     );
     assert_eq!(
         iface.inner.get_source_address_ipv6(&UNIQUE_LOCAL_ADDR1),
-        Ipv6Address::LOOPBACK
+        Ipv6Address::LOCALHOST
     );
     assert_eq!(
         iface.inner.get_source_address_ipv6(&UNIQUE_LOCAL_ADDR2),
-        Ipv6Address::LOOPBACK
+        Ipv6Address::LOCALHOST
     );
     assert_eq!(
         iface.inner.get_source_address_ipv6(&UNIQUE_LOCAL_ADDR3),
-        Ipv6Address::LOOPBACK
+        Ipv6Address::LOCALHOST
     );
     assert_eq!(
         iface
             .inner
-            .get_source_address_ipv6(&Ipv6Address::LINK_LOCAL_ALL_NODES),
-        Ipv6Address::LOOPBACK
+            .get_source_address_ipv6(&IPV6_LINK_LOCAL_ALL_NODES),
+        Ipv6Address::LOCALHOST
     );
     assert_eq!(
         iface.inner.get_source_address_ipv6(&GLOBAL_UNICAST_ADDR1),
-        Ipv6Address::LOOPBACK
+        Ipv6Address::LOCALHOST
     );
     assert_eq!(
         iface.inner.get_source_address_ipv6(&GLOBAL_UNICAST_ADDR2),
-        Ipv6Address::LOOPBACK
+        Ipv6Address::LOCALHOST
     );
 
     assert_eq!(
         iface.get_source_address_ipv6(&LINK_LOCAL_ADDR),
-        Ipv6Address::LOOPBACK
+        Ipv6Address::LOCALHOST
     );
     assert_eq!(
         iface.get_source_address_ipv6(&UNIQUE_LOCAL_ADDR1),
-        Ipv6Address::LOOPBACK
+        Ipv6Address::LOCALHOST
     );
     assert_eq!(
         iface.get_source_address_ipv6(&UNIQUE_LOCAL_ADDR2),
-        Ipv6Address::LOOPBACK
+        Ipv6Address::LOCALHOST
     );
     assert_eq!(
         iface.get_source_address_ipv6(&UNIQUE_LOCAL_ADDR3),
-        Ipv6Address::LOOPBACK
+        Ipv6Address::LOCALHOST
     );
     assert_eq!(
-        iface.get_source_address_ipv6(&Ipv6Address::LINK_LOCAL_ALL_NODES),
-        Ipv6Address::LOOPBACK
+        iface.get_source_address_ipv6(&IPV6_LINK_LOCAL_ALL_NODES),
+        Ipv6Address::LOCALHOST
     );
     assert_eq!(
         iface.get_source_address_ipv6(&GLOBAL_UNICAST_ADDR1),
-        Ipv6Address::LOOPBACK
+        Ipv6Address::LOCALHOST
     );
     assert_eq!(
         iface.get_source_address_ipv6(&GLOBAL_UNICAST_ADDR2),
-        Ipv6Address::LOOPBACK
+        Ipv6Address::LOCALHOST
     );
 }
 
@@ -1292,8 +1290,8 @@ fn test_join_ipv6_multicast_group(#[case] medium: Medium) {
     let (mut iface, mut sockets, mut device) = setup(medium);
 
     let groups = [
-        Ipv6Address::from_parts(&[0xff05, 0, 0, 0, 0, 0, 0, 0x00fb]),
-        Ipv6Address::from_parts(&[0xff0e, 0, 0, 0, 0, 0, 0, 0x0017]),
+        Ipv6Address::new(0xff05, 0, 0, 0, 0, 0, 0, 0x00fb),
+        Ipv6Address::new(0xff0e, 0, 0, 0, 0, 0, 0, 0x0017),
     ];
 
     let timestamp = Instant::from_millis(0);
@@ -1302,9 +1300,9 @@ fn test_join_ipv6_multicast_group(#[case] medium: Medium) {
         iface.join_multicast_group(group).unwrap();
         assert!(iface.has_multicast_group(group));
     }
-    assert!(iface.has_multicast_group(Ipv6Address::LINK_LOCAL_ALL_NODES));
+    assert!(iface.has_multicast_group(IPV6_LINK_LOCAL_ALL_NODES));
     iface.poll(timestamp, &mut device, &mut sockets);
-    assert!(iface.has_multicast_group(Ipv6Address::LINK_LOCAL_ALL_NODES));
+    assert!(iface.has_multicast_group(IPV6_LINK_LOCAL_ALL_NODES));
 
     let reports = recv_icmpv6(&mut device, timestamp);
     assert_eq!(reports.len(), 2);

+ 1 - 1
src/iface/interface/tests/mod.rs

@@ -98,7 +98,7 @@ fn test_handle_udp_broadcast(#[case] medium: Medium) {
     #[cfg(feature = "proto-ipv6")]
     let ip_repr = IpRepr::Ipv6(Ipv6Repr {
         src_addr: src_ip,
-        dst_addr: Ipv6Address::LINK_LOCAL_ALL_NODES,
+        dst_addr: IPV6_LINK_LOCAL_ALL_NODES,
         next_header: IpProtocol::Udp,
         payload_len: udp_repr.header_len() + UDP_PAYLOAD.len(),
         hop_limit: 0x40,

+ 17 - 34
src/iface/interface/tests/sixlowpan.rs

@@ -40,8 +40,8 @@ fn icmp_echo_request(#[case] medium: Medium) {
 
     let response = Some(Packet::new_ipv6(
         Ipv6Repr {
-            src_addr: Ipv6Address::from_parts(&[0xfe80, 0, 0, 0, 0x180b, 0x4242, 0x4242, 0x4242]),
-            dst_addr: Ipv6Address::from_parts(&[0xfe80, 0, 0, 0, 0x241c, 0x2957, 0x34a6, 0x3a62]),
+            src_addr: Ipv6Address::new(0xfe80, 0, 0, 0, 0x180b, 0x4242, 0x4242, 0x4242),
+            dst_addr: Ipv6Address::new(0xfe80, 0, 0, 0, 0x241c, 0x2957, 0x34a6, 0x3a62),
             hop_limit: 64,
             next_header: IpProtocol::Icmpv6,
             payload_len: 64,
@@ -61,7 +61,7 @@ fn icmp_echo_request(#[case] medium: Medium) {
     let (mut iface, mut sockets, _device) = setup(medium);
     iface.update_ip_addrs(|ips| {
         ips.push(IpCidr::Ipv6(Ipv6Cidr::new(
-            Ipv6Address::from_parts(&[0xfe80, 0, 0, 0, 0x180b, 0x4242, 0x4242, 0x4242]),
+            Ipv6Address::new(0xfe80, 0, 0, 0, 0x180b, 0x4242, 0x4242, 0x4242),
             10,
         )))
         .unwrap();
@@ -99,7 +99,7 @@ fn test_echo_request_sixlowpan_128_bytes() {
     let now = iface.inner.now();
 
     iface.inner.neighbor_cache.fill(
-        Ipv6Address([0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0x2, 0, 0, 0, 0, 0, 0, 0]).into(),
+        Ipv6Address::new(0xfe80, 0, 0, 0, 0x0200, 0, 0, 0).into(),
         HardwareAddress::Ieee802154(Ieee802154Address::default()),
         now,
     );
@@ -148,17 +148,11 @@ fn test_echo_request_sixlowpan_128_bytes() {
 
     assert_eq!(
         request_first_part_iphc_repr.src_addr,
-        Ipv6Address([
-            0xfe, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x42, 0x42, 0x42, 0x42, 0x42, 0xb,
-            0x1a,
-        ]),
+        Ipv6Address::new(0xfe80, 0, 0, 0, 0x4042, 0x4242, 0x4242, 0x0b1a),
     );
     assert_eq!(
         request_first_part_iphc_repr.dst_addr,
-        Ipv6Address([
-            0xfe, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x92, 0xfc, 0x48, 0xc2, 0xa4, 0x41, 0xfc,
-            0x76,
-        ]),
+        Ipv6Address::new(0xfe80, 0, 0, 0, 0x92fc, 0x48c2, 0xa441, 0xfc76),
     );
 
     let request_second_part = [
@@ -206,14 +200,8 @@ fn test_echo_request_sixlowpan_128_bytes() {
         result,
         Some(Packet::new_ipv6(
             Ipv6Repr {
-                src_addr: Ipv6Address([
-                    0xfe, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x92, 0xfc, 0x48, 0xc2, 0xa4, 0x41,
-                    0xfc, 0x76,
-                ]),
-                dst_addr: Ipv6Address([
-                    0xfe, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x42, 0x42, 0x42, 0x42, 0x42,
-                    0xb, 0x1a,
-                ]),
+                src_addr: Ipv6Address::new(0xfe80, 0, 0, 0, 0x92fc, 0x48c2, 0xa441, 0xfc76),
+                dst_addr: Ipv6Address::new(0xfe80, 0, 0, 0, 0x4042, 0x4242, 0x4242, 0x0b1a),
                 next_header: IpProtocol::Icmpv6,
                 payload_len: 136,
                 hop_limit: 64,
@@ -227,9 +215,9 @@ fn test_echo_request_sixlowpan_128_bytes() {
     );
 
     iface.inner.neighbor_cache.fill(
-        IpAddress::Ipv6(Ipv6Address([
-            0xfe, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x42, 0x42, 0x42, 0x42, 0x42, 0xb, 0x1a,
-        ])),
+        IpAddress::Ipv6(Ipv6Address::new(
+            0xfe80, 0, 0, 0, 0x4042, 0x4242, 0x4242, 0x0b1a,
+        )),
         HardwareAddress::Ieee802154(Ieee802154Address::default()),
         Instant::now(),
     );
@@ -370,17 +358,12 @@ In at rhoncus tortor. Cras blandit tellus diam, varius vestibulum nibh commodo n
             &udp_data[..],
             udp::UdpMetadata {
                 local_address: Some(
-                    Ipv6Address([
-                        0xfe, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x92, 0xfc, 0x48, 0xc2, 0xa4,
-                        0x41, 0xfc, 0x76,
-                    ])
-                    .into()
+                    Ipv6Address::new(0xfe80, 0, 0, 0, 0x92fc, 0x48c2, 0xa441, 0xfc76).into()
                 ),
                 ..IpEndpoint {
-                    addr: IpAddress::Ipv6(Ipv6Address([
-                        0xfe, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x42, 0x42, 0x42, 0x42,
-                        0x42, 0xb, 0x1a,
-                    ])),
+                    addr: IpAddress::Ipv6(Ipv6Address::new(
+                        0xfe80, 0, 0, 0, 0x4042, 0x4242, 0x4242, 0x0b1a
+                    )),
                     port: 54217,
                 }
                 .into()
@@ -395,8 +378,8 @@ In at rhoncus tortor. Cras blandit tellus diam, varius vestibulum nibh commodo n
         PacketMeta::default(),
         Packet::new_ipv6(
             Ipv6Repr {
-                src_addr: Ipv6Address::default(),
-                dst_addr: Ipv6Address::default(),
+                src_addr: Ipv6Address::UNSPECIFIED,
+                dst_addr: Ipv6Address::UNSPECIFIED,
                 next_header: IpProtocol::Udp,
                 payload_len: udp_data.len(),
                 hop_limit: 64,

+ 14 - 25
src/iface/route.rs

@@ -172,45 +172,34 @@ mod test {
     #[cfg(feature = "proto-ipv6")]
     mod mock {
         use super::super::*;
-        pub const ADDR_1A: Ipv6Address =
-            Ipv6Address([0xfe, 0x80, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 1]);
-        pub const ADDR_1B: Ipv6Address =
-            Ipv6Address([0xfe, 0x80, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 13]);
-        pub const ADDR_1C: Ipv6Address =
-            Ipv6Address([0xfe, 0x80, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 42]);
+        pub const ADDR_1A: Ipv6Address = Ipv6Address::new(0xfe80, 0, 0, 2, 0, 0, 0, 1);
+        pub const ADDR_1B: Ipv6Address = Ipv6Address::new(0xfe80, 0, 0, 2, 0, 0, 0, 13);
+        pub const ADDR_1C: Ipv6Address = Ipv6Address::new(0xfe80, 0, 0, 2, 0, 0, 0, 42);
         pub fn cidr_1() -> Ipv6Cidr {
-            Ipv6Cidr::new(
-                Ipv6Address([0xfe, 0x80, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0]),
-                64,
-            )
+            Ipv6Cidr::new(Ipv6Address::new(0xfe80, 0, 0, 2, 0, 0, 0, 0), 64)
         }
 
-        pub const ADDR_2A: Ipv6Address =
-            Ipv6Address([0xfe, 0x80, 0, 0, 0, 0, 51, 100, 0, 0, 0, 0, 0, 0, 0, 1]);
-        pub const ADDR_2B: Ipv6Address =
-            Ipv6Address([0xfe, 0x80, 0, 0, 0, 0, 51, 100, 0, 0, 0, 0, 0, 0, 0, 21]);
+        pub const ADDR_2A: Ipv6Address = Ipv6Address::new(0xfe80, 0, 0, 0x3364, 0, 0, 0, 1);
+        pub const ADDR_2B: Ipv6Address = Ipv6Address::new(0xfe80, 0, 0, 0x3364, 0, 0, 0, 21);
         pub fn cidr_2() -> Ipv6Cidr {
-            Ipv6Cidr::new(
-                Ipv6Address([0xfe, 0x80, 0, 0, 0, 0, 51, 100, 0, 0, 0, 0, 0, 0, 0, 0]),
-                64,
-            )
+            Ipv6Cidr::new(Ipv6Address::new(0xfe80, 0, 0, 0x3364, 0, 0, 0, 0), 64)
         }
     }
 
     #[cfg(all(feature = "proto-ipv4", not(feature = "proto-ipv6")))]
     mod mock {
         use super::super::*;
-        pub const ADDR_1A: Ipv4Address = Ipv4Address([192, 0, 2, 1]);
-        pub const ADDR_1B: Ipv4Address = Ipv4Address([192, 0, 2, 13]);
-        pub const ADDR_1C: Ipv4Address = Ipv4Address([192, 0, 2, 42]);
+        pub const ADDR_1A: Ipv4Address = Ipv4Address::new(192, 0, 2, 1);
+        pub const ADDR_1B: Ipv4Address = Ipv4Address::new(192, 0, 2, 13);
+        pub const ADDR_1C: Ipv4Address = Ipv4Address::new(192, 0, 2, 42);
         pub fn cidr_1() -> Ipv4Cidr {
-            Ipv4Cidr::new(Ipv4Address([192, 0, 2, 0]), 24)
+            Ipv4Cidr::new(Ipv4Address::new(192, 0, 2, 0), 24)
         }
 
-        pub const ADDR_2A: Ipv4Address = Ipv4Address([198, 51, 100, 1]);
-        pub const ADDR_2B: Ipv4Address = Ipv4Address([198, 51, 100, 21]);
+        pub const ADDR_2A: Ipv4Address = Ipv4Address::new(198, 51, 100, 1);
+        pub const ADDR_2B: Ipv4Address = Ipv4Address::new(198, 51, 100, 21);
         pub fn cidr_2() -> Ipv4Cidr {
-            Ipv4Cidr::new(Ipv4Address([198, 51, 100, 0]), 24)
+            Ipv4Cidr::new(Ipv4Address::new(198, 51, 100, 0), 24)
         }
     }
 

+ 5 - 6
src/iface/rpl/of0.rs

@@ -99,12 +99,11 @@ mod tests {
         let mut parents = ParentSet::default();
 
         parents.add(
-            Ipv6Address::default(),
-            Parent::new(0, Rank::ROOT, Default::default(), Ipv6Address::default()),
+            Ipv6Address::UNSPECIFIED,
+            Parent::new(0, Rank::ROOT, Default::default(), Ipv6Address::UNSPECIFIED),
         );
 
-        let mut address = Ipv6Address::default();
-        address.0[15] = 1;
+        let address = Ipv6Address::new(0, 0, 0, 0, 0, 0, 0, 1);
 
         parents.add(
             address,
@@ -112,7 +111,7 @@ mod tests {
                 0,
                 Rank::new(1024, DEFAULT_MIN_HOP_RANK_INCREASE),
                 Default::default(),
-                Ipv6Address::default(),
+                Ipv6Address::UNSPECIFIED,
             ),
         );
 
@@ -122,7 +121,7 @@ mod tests {
                 0,
                 Rank::ROOT,
                 Default::default(),
-                Ipv6Address::default(),
+                Ipv6Address::UNSPECIFIED,
             ))
         );
     }

+ 8 - 11
src/iface/rpl/parents.rs

@@ -87,17 +87,17 @@ mod tests {
     fn add_parent() {
         let mut set = ParentSet::default();
         set.add(
-            Default::default(),
-            Parent::new(0, Rank::ROOT, Default::default(), Default::default()),
+            Ipv6Address::UNSPECIFIED,
+            Parent::new(0, Rank::ROOT, Default::default(), Ipv6Address::UNSPECIFIED),
         );
 
         assert_eq!(
-            set.find(&Default::default()),
+            set.find(&Ipv6Address::UNSPECIFIED),
             Some(&Parent::new(
                 0,
                 Rank::ROOT,
                 Default::default(),
-                Default::default()
+                Ipv6Address::UNSPECIFIED
             ))
         );
     }
@@ -107,11 +107,10 @@ mod tests {
         use super::super::consts::DEFAULT_MIN_HOP_RANK_INCREASE;
         let mut set = ParentSet::default();
 
-        let mut last_address = Default::default();
+        let mut last_address = Ipv6Address::UNSPECIFIED;
         for i in 0..RPL_PARENTS_BUFFER_COUNT {
             let i = i as u16;
-            let mut address = Ipv6Address::default();
-            address.0[15] = i as u8;
+            let address = Ipv6Address::new(0, 0, 0, 0, 0, 0, 0, i as _);
             last_address = address;
 
             set.add(
@@ -137,8 +136,7 @@ mod tests {
 
         // This one is not added to the set, because its Rank is worse than any other parent in the
         // set.
-        let mut address = Ipv6Address::default();
-        address.0[15] = 8;
+        let address = Ipv6Address::new(0, 0, 0, 0, 0, 0, 0, 8);
         set.add(
             address,
             Parent::new(
@@ -151,8 +149,7 @@ mod tests {
         assert_eq!(set.find(&address), None);
 
         /// This Parent has a better rank than the last one in the set.
-        let mut address = Ipv6Address::default();
-        address.0[15] = 9;
+        let address = Ipv6Address::new(0, 0, 0, 0, 0, 0, 0, 9);
         set.add(
             address,
             Parent::new(

+ 1 - 5
src/iface/rpl/relations.rs

@@ -73,11 +73,7 @@ mod tests {
 
     fn addresses(count: usize) -> Vec<Ipv6Address> {
         (0..count)
-            .map(|i| {
-                let mut ip = Ipv6Address::default();
-                ip.0[0] = i as u8;
-                ip
-            })
+            .map(|i| Ipv6Address::new(0, 0, 0, 0, 0, 0, 0, i as _))
             .collect()
     }
 

+ 1 - 1
src/lib.rs

@@ -65,7 +65,7 @@
 //!
 //! # Minimum Supported Rust Version (MSRV)
 //!
-//! This crate is guaranteed to compile on stable Rust 1.77 and up with any valid set of features.
+//! This crate is guaranteed to compile on stable Rust 1.80 and up with any valid set of features.
 //! It *might* compile on older versions but that may change in any new patch release.
 //!
 //! The exception is when using the `defmt` feature, in which case `defmt`'s MSRV applies, which

+ 1 - 1
src/macros.rs

@@ -132,7 +132,7 @@ macro_rules! get {
 #[cfg(feature = "proto-rpl")]
 macro_rules! set {
     ($buffer:expr, address: $address:ident, field: $field:expr $(,)?) => {{
-        $buffer.as_mut()[$field].copy_from_slice($address.as_bytes());
+        $buffer.as_mut()[$field].copy_from_slice(&$address.octets());
     }};
 
     ($buffer:expr, $value:ident, field: $field:expr $(,)?) => {

+ 9 - 127
src/parsers.rs

@@ -10,7 +10,7 @@ use core::str::FromStr;
 use crate::wire::EthernetAddress;
 use crate::wire::{IpAddress, IpCidr, IpEndpoint};
 #[cfg(feature = "proto-ipv4")]
-use crate::wire::{Ipv4Address, Ipv4Cidr};
+use crate::wire::{Ipv4Address, Ipv4AddressExt, Ipv4Cidr};
 #[cfg(feature = "proto-ipv6")]
 use crate::wire::{Ipv6Address, Ipv6Cidr};
 
@@ -277,7 +277,7 @@ impl<'a> Parser<'a> {
         // end of the address.
         addr[8 - tail_idx..].copy_from_slice(&tail[..tail_idx]);
 
-        Ok(Ipv6Address::from_parts(&addr))
+        Ok(Ipv6Address::from(addr))
     }
 
     fn accept_ipv4_octets(&mut self) -> Result<[u8; 4]> {
@@ -294,7 +294,7 @@ impl<'a> Parser<'a> {
     #[cfg(feature = "proto-ipv4")]
     fn accept_ipv4(&mut self) -> Result<Ipv4Address> {
         let octets = self.accept_ipv4_octets()?;
-        Ok(Ipv4Address(octets))
+        Ok(Ipv4Address::from_bytes(&octets))
     }
 
     fn accept_ip(&mut self) -> Result<IpAddress> {
@@ -383,26 +383,6 @@ impl FromStr for EthernetAddress {
     }
 }
 
-#[cfg(feature = "proto-ipv4")]
-impl FromStr for Ipv4Address {
-    type Err = ();
-
-    /// Parse a string representation of an IPv4 address.
-    fn from_str(s: &str) -> Result<Ipv4Address> {
-        Parser::new(s).until_eof(|p| p.accept_ipv4())
-    }
-}
-
-#[cfg(feature = "proto-ipv6")]
-impl FromStr for Ipv6Address {
-    type Err = ();
-
-    /// Parse a string representation of an IPv6 address.
-    fn from_str(s: &str) -> Result<Ipv6Address> {
-        Parser::new(s).until_eof(|p| p.accept_ipv6())
-    }
-}
-
 impl FromStr for IpAddress {
     type Err = ();
 
@@ -526,111 +506,13 @@ mod test {
         assert_eq!(EthernetAddress::from_str("02:00:00:00:00:0x"), Err(()));
     }
 
-    #[test]
-    #[cfg(feature = "proto-ipv4")]
-    fn test_ipv4() {
-        assert_eq!(Ipv4Address::from_str(""), Err(()));
-        assert_eq!(
-            Ipv4Address::from_str("1.2.3.4"),
-            Ok(Ipv4Address([1, 2, 3, 4]))
-        );
-        assert_eq!(
-            Ipv4Address::from_str("001.2.3.4"),
-            Ok(Ipv4Address([1, 2, 3, 4]))
-        );
-        assert_eq!(Ipv4Address::from_str("0001.2.3.4"), Err(()));
-        assert_eq!(Ipv4Address::from_str("999.2.3.4"), Err(()));
-        assert_eq!(Ipv4Address::from_str("1.2.3.4.5"), Err(()));
-        assert_eq!(Ipv4Address::from_str("1.2.3"), Err(()));
-        assert_eq!(Ipv4Address::from_str("1.2.3."), Err(()));
-        assert_eq!(Ipv4Address::from_str("1.2.3.4."), Err(()));
-    }
-
-    #[test]
-    #[cfg(feature = "proto-ipv6")]
-    fn test_ipv6() {
-        // Obviously not valid
-        assert_eq!(Ipv6Address::from_str(""), Err(()));
-        assert_eq!(
-            Ipv6Address::from_str("fe80:0:0:0:0:0:0:1"),
-            Ok(Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 1))
-        );
-        assert_eq!(Ipv6Address::from_str("::1"), Ok(Ipv6Address::LOOPBACK));
-        assert_eq!(Ipv6Address::from_str("::"), Ok(Ipv6Address::UNSPECIFIED));
-        assert_eq!(
-            Ipv6Address::from_str("fe80::1"),
-            Ok(Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 1))
-        );
-        assert_eq!(
-            Ipv6Address::from_str("1234:5678::"),
-            Ok(Ipv6Address::new(0x1234, 0x5678, 0, 0, 0, 0, 0, 0))
-        );
-        assert_eq!(
-            Ipv6Address::from_str("1234:5678::8765:4321"),
-            Ok(Ipv6Address::new(0x1234, 0x5678, 0, 0, 0, 0, 0x8765, 0x4321))
-        );
-        // Two double colons in address
-        assert_eq!(Ipv6Address::from_str("1234:5678::1::1"), Err(()));
-        assert_eq!(
-            Ipv6Address::from_str("4444:333:22:1::4"),
-            Ok(Ipv6Address::new(0x4444, 0x0333, 0x0022, 0x0001, 0, 0, 0, 4))
-        );
-        assert_eq!(
-            Ipv6Address::from_str("1:1:1:1:1:1::"),
-            Ok(Ipv6Address::new(1, 1, 1, 1, 1, 1, 0, 0))
-        );
-        assert_eq!(
-            Ipv6Address::from_str("::1:1:1:1:1:1"),
-            Ok(Ipv6Address::new(0, 0, 1, 1, 1, 1, 1, 1))
-        );
-        assert_eq!(Ipv6Address::from_str("::1:1:1:1:1:1:1"), Err(()));
-        // Double colon appears too late indicating an address that is too long
-        assert_eq!(Ipv6Address::from_str("1:1:1:1:1:1:1::"), Err(()));
-        // Section after double colon is too long for a valid address
-        assert_eq!(Ipv6Address::from_str("::1:1:1:1:1:1:1"), Err(()));
-        // Obviously too long
-        assert_eq!(Ipv6Address::from_str("1:1:1:1:1:1:1:1:1"), Err(()));
-        // Address is too short
-        assert_eq!(Ipv6Address::from_str("1:1:1:1:1:1:1"), Err(()));
-        // Long number
-        assert_eq!(Ipv6Address::from_str("::000001"), Err(()));
-        // IPv4-Mapped address
-        assert_eq!(
-            Ipv6Address::from_str("::ffff:192.168.1.1"),
-            Ok(Ipv6Address([
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 192, 168, 1, 1
-            ]))
-        );
-        assert_eq!(
-            Ipv6Address::from_str("0:0:0:0:0:ffff:192.168.1.1"),
-            Ok(Ipv6Address([
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 192, 168, 1, 1
-            ]))
-        );
-        assert_eq!(
-            Ipv6Address::from_str("0::ffff:192.168.1.1"),
-            Ok(Ipv6Address([
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 192, 168, 1, 1
-            ]))
-        );
-        // Only ffff is allowed in position 6 when IPv4 mapped
-        assert_eq!(Ipv6Address::from_str("0:0:0:0:0:eeee:192.168.1.1"), Err(()));
-        // Positions 1-5 must be 0 when IPv4 mapped
-        assert_eq!(Ipv6Address::from_str("0:0:0:0:1:ffff:192.168.1.1"), Err(()));
-        assert_eq!(Ipv6Address::from_str("1::ffff:192.168.1.1"), Err(()));
-        // Out of range ipv4 octet
-        assert_eq!(Ipv6Address::from_str("0:0:0:0:0:ffff:256.168.1.1"), Err(()));
-        // Invalid hex in ipv4 octet
-        assert_eq!(Ipv6Address::from_str("0:0:0:0:0:ffff:c0.168.1.1"), Err(()));
-    }
-
     #[test]
     #[cfg(feature = "proto-ipv4")]
     fn test_ip_ipv4() {
         assert_eq!(IpAddress::from_str(""), Err(()));
         assert_eq!(
             IpAddress::from_str("1.2.3.4"),
-            Ok(IpAddress::Ipv4(Ipv4Address([1, 2, 3, 4])))
+            Ok(IpAddress::Ipv4(Ipv4Address::new(1, 2, 3, 4)))
         );
         assert_eq!(IpAddress::from_str("x"), Err(()));
     }
@@ -654,19 +536,19 @@ mod test {
         let tests = [
             (
                 "127.0.0.1/8",
-                Ok(Ipv4Cidr::new(Ipv4Address([127, 0, 0, 1]), 8u8)),
+                Ok(Ipv4Cidr::new(Ipv4Address::new(127, 0, 0, 1), 8u8)),
             ),
             (
                 "192.168.1.1/24",
-                Ok(Ipv4Cidr::new(Ipv4Address([192, 168, 1, 1]), 24u8)),
+                Ok(Ipv4Cidr::new(Ipv4Address::new(192, 168, 1, 1), 24u8)),
             ),
             (
                 "8.8.8.8/32",
-                Ok(Ipv4Cidr::new(Ipv4Address([8, 8, 8, 8]), 32u8)),
+                Ok(Ipv4Cidr::new(Ipv4Address::new(8, 8, 8, 8), 32u8)),
             ),
             (
                 "8.8.8.8/0",
-                Ok(Ipv4Cidr::new(Ipv4Address([8, 8, 8, 8]), 0u8)),
+                Ok(Ipv4Cidr::new(Ipv4Address::new(8, 8, 8, 8), 0u8)),
             ),
             ("", Err(())),
             ("1", Err(())),
@@ -698,7 +580,7 @@ mod test {
                     64u8,
                 )),
             ),
-            ("::1/128", Ok(Ipv6Cidr::new(Ipv6Address::LOOPBACK, 128u8))),
+            ("::1/128", Ok(Ipv6Cidr::new(Ipv6Address::LOCALHOST, 128u8))),
             ("::/128", Ok(Ipv6Cidr::new(Ipv6Address::UNSPECIFIED, 128u8))),
             (
                 "fe80:0:0:0:0:0:0:1/64",

+ 2 - 2
src/phy/fault_injector.rs

@@ -315,10 +315,10 @@ impl<'a, Tx: phy::TxToken> phy::TxToken for TxToken<'a, Tx> {
             return f(&mut self.junk[..len]);
         }
 
-        self.token.consume(len, |mut buf| {
+        self.token.consume(len, |buf| {
             if self.state.maybe(self.config.corrupt_pct) {
                 net_trace!("tx: corrupting a packet");
-                self.state.corrupt(&mut buf)
+                self.state.corrupt(&mut *buf);
             }
             f(buf)
         })

+ 12 - 11
src/socket/dhcpv4.rs

@@ -5,8 +5,9 @@ use crate::iface::Context;
 use crate::time::{Duration, Instant};
 use crate::wire::dhcpv4::field as dhcpv4_field;
 use crate::wire::{
-    DhcpMessageType, DhcpPacket, DhcpRepr, IpAddress, IpProtocol, Ipv4Address, Ipv4Cidr, Ipv4Repr,
-    UdpRepr, DHCP_CLIENT_PORT, DHCP_MAX_DNS_SERVER_COUNT, DHCP_SERVER_PORT, UDP_HEADER_LEN,
+    DhcpMessageType, DhcpPacket, DhcpRepr, IpAddress, IpProtocol, Ipv4Address, Ipv4AddressExt,
+    Ipv4Cidr, Ipv4Repr, UdpRepr, DHCP_CLIENT_PORT, DHCP_MAX_DNS_SERVER_COUNT, DHCP_SERVER_PORT,
+    UDP_HEADER_LEN,
 };
 use crate::wire::{DhcpOption, HardwareAddress};
 use heapless::Vec;
@@ -365,7 +366,7 @@ impl<'a> Socket<'a> {
 
         match (&mut self.state, dhcp_repr.message_type) {
             (ClientState::Discovering(_state), DhcpMessageType::Offer) => {
-                if !dhcp_repr.your_ip.is_unicast() {
+                if !dhcp_repr.your_ip.x_is_unicast() {
                     net_debug!("DHCP ignoring OFFER because your_ip is not unicast");
                     return;
                 }
@@ -461,7 +462,7 @@ impl<'a> Socket<'a> {
             }
         };
 
-        if !dhcp_repr.your_ip.is_unicast() {
+        if !dhcp_repr.your_ip.x_is_unicast() {
             net_debug!("DHCP ignoring ACK because your_ip is not unicast");
             return None;
         }
@@ -482,7 +483,7 @@ impl<'a> Socket<'a> {
             .dns_servers
             .iter()
             .flatten()
-            .filter(|s| s.is_unicast())
+            .filter(|s| s.x_is_unicast())
             .for_each(|a| {
                 // This will never produce an error, as both the arrays and `dns_servers`
                 // have length DHCP_MAX_DNS_SERVER_COUNT
@@ -880,14 +881,14 @@ mod test {
 
     const TXID: u32 = 0x12345678;
 
-    const MY_IP: Ipv4Address = Ipv4Address([192, 168, 1, 42]);
-    const SERVER_IP: Ipv4Address = Ipv4Address([192, 168, 1, 1]);
-    const DNS_IP_1: Ipv4Address = Ipv4Address([1, 1, 1, 1]);
-    const DNS_IP_2: Ipv4Address = Ipv4Address([1, 1, 1, 2]);
-    const DNS_IP_3: Ipv4Address = Ipv4Address([1, 1, 1, 3]);
+    const MY_IP: Ipv4Address = Ipv4Address::new(192, 168, 1, 42);
+    const SERVER_IP: Ipv4Address = Ipv4Address::new(192, 168, 1, 1);
+    const DNS_IP_1: Ipv4Address = Ipv4Address::new(1, 1, 1, 1);
+    const DNS_IP_2: Ipv4Address = Ipv4Address::new(1, 1, 1, 2);
+    const DNS_IP_3: Ipv4Address = Ipv4Address::new(1, 1, 1, 3);
     const DNS_IPS: &[Ipv4Address] = &[DNS_IP_1, DNS_IP_2, DNS_IP_3];
 
-    const MASK_24: Ipv4Address = Ipv4Address([255, 255, 255, 0]);
+    const MASK_24: Ipv4Address = Ipv4Address::new(255, 255, 255, 0);
 
     const MY_MAC: EthernetAddress = EthernetAddress([0x02, 0x02, 0x02, 0x02, 0x02, 0x02]);
 

+ 4 - 4
src/socket/dns.rs

@@ -22,13 +22,13 @@ const RETRANSMIT_TIMEOUT: Duration = Duration::from_millis(10_000); // Should ge
 
 #[cfg(feature = "proto-ipv6")]
 #[allow(unused)]
-const MDNS_IPV6_ADDR: IpAddress = IpAddress::Ipv6(crate::wire::Ipv6Address([
-    0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb,
-]));
+const MDNS_IPV6_ADDR: IpAddress = IpAddress::Ipv6(crate::wire::Ipv6Address::new(
+    0xff02, 0, 0, 0, 0, 0, 0, 0xfb,
+));
 
 #[cfg(feature = "proto-ipv4")]
 #[allow(unused)]
-const MDNS_IPV4_ADDR: IpAddress = IpAddress::Ipv4(crate::wire::Ipv4Address([224, 0, 0, 251]));
+const MDNS_IPV4_ADDR: IpAddress = IpAddress::Ipv4(crate::wire::Ipv4Address::new(224, 0, 0, 251));
 
 /// Error returned by [`Socket::start_query`]
 #[derive(Debug, PartialEq, Eq, Clone, Copy)]

+ 6 - 8
src/socket/icmp.rs

@@ -678,8 +678,8 @@ mod test_ipv4 {
     use super::tests_common::*;
     use crate::wire::{Icmpv4DstUnreachable, IpEndpoint, Ipv4Address};
 
-    const REMOTE_IPV4: Ipv4Address = Ipv4Address([192, 168, 1, 2]);
-    const LOCAL_IPV4: Ipv4Address = Ipv4Address([192, 168, 1, 1]);
+    const REMOTE_IPV4: Ipv4Address = Ipv4Address::new(192, 168, 1, 2);
+    const LOCAL_IPV4: Ipv4Address = Ipv4Address::new(192, 168, 1, 1);
     const LOCAL_END_V4: IpEndpoint = IpEndpoint {
         addr: IpAddress::Ipv4(LOCAL_IPV4),
         port: LOCAL_PORT,
@@ -711,7 +711,7 @@ mod test_ipv4 {
     fn test_send_unaddressable() {
         let mut socket = socket(buffer(0), buffer(1));
         assert_eq!(
-            socket.send_slice(b"abcdef", IpAddress::Ipv4(Ipv4Address::default())),
+            socket.send_slice(b"abcdef", IpAddress::Ipv4(Ipv4Address::new(0, 0, 0, 0))),
             Err(SendError::Unaddressable)
         );
         assert_eq!(socket.send_slice(b"abcdef", REMOTE_IPV4.into()), Ok(()));
@@ -940,10 +940,8 @@ mod test_ipv6 {
 
     use crate::wire::{Icmpv6DstUnreachable, IpEndpoint, Ipv6Address};
 
-    const REMOTE_IPV6: Ipv6Address =
-        Ipv6Address([0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2]);
-    const LOCAL_IPV6: Ipv6Address =
-        Ipv6Address([0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]);
+    const REMOTE_IPV6: Ipv6Address = Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 2);
+    const LOCAL_IPV6: Ipv6Address = Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 1);
     const LOCAL_END_V6: IpEndpoint = IpEndpoint {
         addr: IpAddress::Ipv6(LOCAL_IPV6),
         port: LOCAL_PORT,
@@ -974,7 +972,7 @@ mod test_ipv6 {
     fn test_send_unaddressable() {
         let mut socket = socket(buffer(0), buffer(1));
         assert_eq!(
-            socket.send_slice(b"abcdef", IpAddress::Ipv6(Ipv6Address::default())),
+            socket.send_slice(b"abcdef", IpAddress::Ipv6(Ipv6Address::UNSPECIFIED)),
             Err(SendError::Unaddressable)
         );
         assert_eq!(socket.send_slice(b"abcdef", REMOTE_IPV6.into()), Ok(()));

+ 4 - 10
src/socket/raw.rs

@@ -494,8 +494,8 @@ mod test {
 
         pub const IP_PROTO: u8 = 63;
         pub const HEADER_REPR: IpRepr = IpRepr::Ipv4(Ipv4Repr {
-            src_addr: Ipv4Address([10, 0, 0, 1]),
-            dst_addr: Ipv4Address([10, 0, 0, 2]),
+            src_addr: Ipv4Address::new(10, 0, 0, 1),
+            dst_addr: Ipv4Address::new(10, 0, 0, 2),
             next_header: IpProtocol::Unknown(IP_PROTO),
             payload_len: 4,
             hop_limit: 64,
@@ -525,14 +525,8 @@ mod test {
 
         pub const IP_PROTO: u8 = 63;
         pub const HEADER_REPR: IpRepr = IpRepr::Ipv6(Ipv6Repr {
-            src_addr: Ipv6Address([
-                0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                0x00, 0x01,
-            ]),
-            dst_addr: Ipv6Address([
-                0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                0x00, 0x02,
-            ]),
+            src_addr: Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 1),
+            dst_addr: Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 2),
             next_header: IpProtocol::Unknown(IP_PROTO),
             payload_len: 4,
             hop_limit: 64,

+ 28 - 24
src/socket/tcp.rs

@@ -586,6 +586,7 @@ impl<'a> Socket<'a> {
     /// * Small embedded processors (such as Cortex-M0, Cortex-M1, and Cortex-M3) do not have an FPU, and floating point operations consume significant amounts of CPU time and Flash space.
     /// * Interrupt handlers should almost always avoid floating-point operations.
     /// * Kernel-mode code on desktop processors usually avoids FPU operations to reduce the penalty of saving and restoring FPU registers.
+    ///
     /// In all these cases, `CongestionControl::Reno` is a better choice of congestion control algorithm.
     pub fn set_congestion_control(&mut self, congestion_control: CongestionControl) {
         use congestion::*;
@@ -1967,7 +1968,7 @@ impl<'a> Socket<'a> {
                         "received duplicate ACK for seq {} (duplicate nr {}{})",
                         ack_number,
                         self.local_rx_dup_acks,
-                        if self.local_rx_dup_acks == u8::max_value() {
+                        if self.local_rx_dup_acks == u8::MAX {
                             "+"
                         } else {
                             ""
@@ -2569,7 +2570,6 @@ impl<'a> fmt::Write for Socket<'a> {
 mod test {
     use super::*;
     use crate::wire::IpRepr;
-    use core::i32;
     use std::ops::{Deref, DerefMut};
     use std::vec::Vec;
 
@@ -2583,14 +2583,6 @@ mod test {
         addr: None,
         port: LOCAL_PORT,
     };
-    const LOCAL_END: IpEndpoint = IpEndpoint {
-        addr: LOCAL_ADDR.into_address(),
-        port: LOCAL_PORT,
-    };
-    const REMOTE_END: IpEndpoint = IpEndpoint {
-        addr: REMOTE_ADDR.into_address(),
-        port: REMOTE_PORT,
-    };
     const TUPLE: Tuple = Tuple {
         local: LOCAL_END,
         remote: REMOTE_END,
@@ -2604,27 +2596,39 @@ mod test {
             use crate::wire::Ipv4Repr as IpvXRepr;
             use IpRepr::Ipv4 as IpReprIpvX;
 
-            const LOCAL_ADDR: IpvXAddress = IpvXAddress([192, 168, 1, 1]);
-            const REMOTE_ADDR: IpvXAddress = IpvXAddress([192, 168, 1, 2]);
-            const OTHER_ADDR: IpvXAddress = IpvXAddress([192, 168, 1, 3]);
+            const LOCAL_ADDR: IpvXAddress = IpvXAddress::new(192, 168, 1, 1);
+            const REMOTE_ADDR: IpvXAddress = IpvXAddress::new(192, 168, 1, 2);
+            const OTHER_ADDR: IpvXAddress = IpvXAddress::new(192, 168, 1, 3);
 
             const BASE_MSS: u16 = 1460;
+
+            const LOCAL_END: IpEndpoint = IpEndpoint {
+                addr: IpAddress::Ipv4(LOCAL_ADDR),
+                port: LOCAL_PORT,
+            };
+            const REMOTE_END: IpEndpoint = IpEndpoint {
+                addr: IpAddress::Ipv4(REMOTE_ADDR),
+                port: REMOTE_PORT,
+            };
         } else {
             use crate::wire::Ipv6Address as IpvXAddress;
             use crate::wire::Ipv6Repr as IpvXRepr;
             use IpRepr::Ipv6 as IpReprIpvX;
 
-            const LOCAL_ADDR: IpvXAddress = IpvXAddress([
-                0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
-            ]);
-            const REMOTE_ADDR: IpvXAddress = IpvXAddress([
-                0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,
-            ]);
-            const OTHER_ADDR: IpvXAddress = IpvXAddress([
-                0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,
-            ]);
+            const LOCAL_ADDR: IpvXAddress = IpvXAddress::new(0xfe80, 0, 0, 0, 0, 0, 0, 1);
+            const REMOTE_ADDR: IpvXAddress = IpvXAddress::new(0xfe80, 0, 0, 0, 0, 0, 0, 2);
+            const OTHER_ADDR: IpvXAddress = IpvXAddress::new(0xfe80, 0, 0, 0, 0, 0, 0, 3);
 
             const BASE_MSS: u16 = 1440;
+
+            const LOCAL_END: IpEndpoint = IpEndpoint {
+                addr: IpAddress::Ipv6(LOCAL_ADDR),
+                port: LOCAL_PORT,
+            };
+            const REMOTE_END: IpEndpoint = IpEndpoint {
+                addr: IpAddress::Ipv6(REMOTE_ADDR),
+                port: REMOTE_PORT,
+            };
         }
     }
 
@@ -6126,7 +6130,7 @@ mod test {
         });
 
         // A lot of retransmits happen here
-        s.local_rx_dup_acks = u8::max_value() - 1;
+        s.local_rx_dup_acks = u8::MAX - 1;
 
         // Send 3 more ACKs, which could overflow local_rx_dup_acks,
         // but intended behaviour is that we saturate the bounds
@@ -6148,7 +6152,7 @@ mod test {
         });
         assert_eq!(
             s.local_rx_dup_acks,
-            u8::max_value(),
+            u8::MAX,
             "duplicate ACK count should not overflow but saturate"
         );
     }

+ 24 - 20
src/socket/udp.rs

@@ -619,34 +619,38 @@ mod test {
             use crate::wire::Ipv4Repr as IpvXRepr;
             use IpRepr::Ipv4 as IpReprIpvX;
 
-            const LOCAL_ADDR: IpvXAddress = IpvXAddress([192, 168, 1, 1]);
-            const REMOTE_ADDR: IpvXAddress = IpvXAddress([192, 168, 1, 2]);
-            const OTHER_ADDR: IpvXAddress = IpvXAddress([192, 168, 1, 3]);
+            const LOCAL_ADDR: IpvXAddress = IpvXAddress::new(192, 168, 1, 1);
+            const REMOTE_ADDR: IpvXAddress = IpvXAddress::new(192, 168, 1, 2);
+            const OTHER_ADDR: IpvXAddress = IpvXAddress::new(192, 168, 1, 3);
+
+            const LOCAL_END: IpEndpoint = IpEndpoint {
+                addr: IpAddress::Ipv4(LOCAL_ADDR),
+                port: LOCAL_PORT,
+            };
+            const REMOTE_END: IpEndpoint = IpEndpoint {
+                addr: IpAddress::Ipv4(REMOTE_ADDR),
+                port: REMOTE_PORT,
+            };
         } else {
             use crate::wire::Ipv6Address as IpvXAddress;
             use crate::wire::Ipv6Repr as IpvXRepr;
             use IpRepr::Ipv6 as IpReprIpvX;
 
-            const LOCAL_ADDR: IpvXAddress = IpvXAddress([
-                0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
-            ]);
-            const REMOTE_ADDR: IpvXAddress = IpvXAddress([
-                0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,
-            ]);
-            const OTHER_ADDR: IpvXAddress = IpvXAddress([
-                0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,
-            ]);
+            const LOCAL_ADDR: IpvXAddress = IpvXAddress::new(0xfe80, 0, 0, 0, 0, 0, 0, 1);
+            const REMOTE_ADDR: IpvXAddress = IpvXAddress::new(0xfe80, 0, 0, 0, 0, 0, 0, 2);
+            const OTHER_ADDR: IpvXAddress = IpvXAddress::new(0xfe80, 0, 0, 0, 0, 0, 0, 3);
+
+            const LOCAL_END: IpEndpoint = IpEndpoint {
+                addr: IpAddress::Ipv6(LOCAL_ADDR),
+                port: LOCAL_PORT,
+            };
+            const REMOTE_END: IpEndpoint = IpEndpoint {
+                addr: IpAddress::Ipv6(REMOTE_ADDR),
+                port: REMOTE_PORT,
+            };
         }
     }
 
-    pub const LOCAL_END: IpEndpoint = IpEndpoint {
-        addr: LOCAL_ADDR.into_address(),
-        port: LOCAL_PORT,
-    };
-    pub const REMOTE_END: IpEndpoint = IpEndpoint {
-        addr: REMOTE_ADDR.into_address(),
-        port: REMOTE_PORT,
-    };
     fn remote_metadata_with_local() -> UdpMetadata {
         // Would be great as a const once we have const `.into()`.
         UdpMetadata {

+ 3 - 4
src/wire/arp.rs

@@ -2,6 +2,7 @@ use byteorder::{ByteOrder, NetworkEndian};
 use core::fmt;
 
 use super::{Error, Result};
+use super::{EthernetAddress, Ipv4Address, Ipv4AddressExt};
 
 pub use super::EthernetProtocol as Protocol;
 
@@ -250,8 +251,6 @@ impl<T: AsRef<[u8]>> AsRef<[u8]> for Packet<T> {
     }
 }
 
-use crate::wire::{EthernetAddress, Ipv4Address};
-
 /// A high-level representation of an Address Resolution Protocol packet.
 #[derive(Debug, PartialEq, Eq, Clone, Copy)]
 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
@@ -313,9 +312,9 @@ impl Repr {
                 packet.set_protocol_len(4);
                 packet.set_operation(operation);
                 packet.set_source_hardware_addr(source_hardware_addr.as_bytes());
-                packet.set_source_protocol_addr(source_protocol_addr.as_bytes());
+                packet.set_source_protocol_addr(&source_protocol_addr.octets());
                 packet.set_target_hardware_addr(target_hardware_addr.as_bytes());
-                packet.set_target_protocol_addr(target_protocol_addr.as_bytes());
+                packet.set_target_protocol_addr(&target_protocol_addr.octets());
             }
         }
     }

+ 21 - 21
src/wire/dhcpv4.rs

@@ -7,7 +7,7 @@ use heapless::Vec;
 
 use super::{Error, Result};
 use crate::wire::arp::Hardware;
-use crate::wire::{EthernetAddress, Ipv4Address};
+use crate::wire::{EthernetAddress, Ipv4Address, Ipv4AddressExt};
 
 pub const SERVER_PORT: u16 = 67;
 pub const CLIENT_PORT: u16 = 68;
@@ -443,7 +443,7 @@ impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
     pub fn set_hardware_type(&mut self, value: Hardware) {
         let data = self.buffer.as_mut();
         let number: u16 = value.into();
-        assert!(number <= u16::from(u8::max_value())); // TODO: Replace with TryFrom when it's stable
+        assert!(number <= u16::from(u8::MAX)); // TODO: Replace with TryFrom when it's stable
         data[field::HTYPE] = number as u8;
     }
 
@@ -503,25 +503,25 @@ impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
     /// and can respond to ARP requests”.
     pub fn set_client_ip(&mut self, value: Ipv4Address) {
         let field = &mut self.buffer.as_mut()[field::CIADDR];
-        field.copy_from_slice(value.as_bytes());
+        field.copy_from_slice(&value.octets());
     }
 
     /// Sets the value of the `yiaddr` field.
     pub fn set_your_ip(&mut self, value: Ipv4Address) {
         let field = &mut self.buffer.as_mut()[field::YIADDR];
-        field.copy_from_slice(value.as_bytes());
+        field.copy_from_slice(&value.octets());
     }
 
     /// Sets the value of the `siaddr` field.
     pub fn set_server_ip(&mut self, value: Ipv4Address) {
         let field = &mut self.buffer.as_mut()[field::SIADDR];
-        field.copy_from_slice(value.as_bytes());
+        field.copy_from_slice(&value.octets());
     }
 
     /// Sets the value of the `giaddr` field.
     pub fn set_relay_agent_ip(&mut self, value: Ipv4Address) {
         let field = &mut self.buffer.as_mut()[field::GIADDR];
-        field.copy_from_slice(value.as_bytes());
+        field.copy_from_slice(&value.octets());
     }
 
     /// Sets the flags to the specified value.
@@ -881,26 +881,26 @@ impl<'a> Repr<'a> {
             if let Some(val) = &self.server_identifier {
                 options.emit(DhcpOption {
                     kind: field::OPT_SERVER_IDENTIFIER,
-                    data: val.as_bytes(),
+                    data: &val.octets(),
                 })?;
             }
 
             if let Some(val) = &self.router {
                 options.emit(DhcpOption {
                     kind: field::OPT_ROUTER,
-                    data: val.as_bytes(),
+                    data: &val.octets(),
                 })?;
             }
             if let Some(val) = &self.subnet_mask {
                 options.emit(DhcpOption {
                     kind: field::OPT_SUBNET_MASK,
-                    data: val.as_bytes(),
+                    data: &val.octets(),
                 })?;
             }
             if let Some(val) = &self.requested_ip {
                 options.emit(DhcpOption {
                     kind: field::OPT_REQUESTED_IP,
-                    data: val.as_bytes(),
+                    data: &val.octets(),
                 })?;
             }
             if let Some(val) = &self.max_size {
@@ -930,7 +930,7 @@ impl<'a> Repr<'a> {
                     .iter()
                     .enumerate()
                     .inspect(|(i, ip)| {
-                        servers[(i * IP_SIZE)..((i + 1) * IP_SIZE)].copy_from_slice(ip.as_bytes());
+                        servers[(i * IP_SIZE)..((i + 1) * IP_SIZE)].copy_from_slice(&ip.octets());
                     })
                     .count()
                     * IP_SIZE;
@@ -1029,7 +1029,7 @@ mod test {
         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     ];
 
-    const IP_NULL: Ipv4Address = Ipv4Address([0, 0, 0, 0]);
+    const IP_NULL: Ipv4Address = Ipv4Address::new(0, 0, 0, 0);
     const CLIENT_MAC: EthernetAddress = EthernetAddress([0x0, 0x0b, 0x82, 0x01, 0xfc, 0x42]);
     const DHCP_SIZE: u16 = 1500;
 
@@ -1236,9 +1236,9 @@ mod test {
             let mut repr = offer_repr();
             repr.dns_servers = Some(
                 Vec::from_slice(&[
-                    Ipv4Address([163, 1, 74, 6]),
-                    Ipv4Address([163, 1, 74, 7]),
-                    Ipv4Address([163, 1, 74, 3]),
+                    Ipv4Address::new(163, 1, 74, 6),
+                    Ipv4Address::new(163, 1, 74, 7),
+                    Ipv4Address::new(163, 1, 74, 3),
                 ])
                 .unwrap(),
             );
@@ -1255,9 +1255,9 @@ mod test {
             repr_parsed.dns_servers,
             Some(
                 Vec::from_slice(&[
-                    Ipv4Address([163, 1, 74, 6]),
-                    Ipv4Address([163, 1, 74, 7]),
-                    Ipv4Address([163, 1, 74, 3]),
+                    Ipv4Address::new(163, 1, 74, 6),
+                    Ipv4Address::new(163, 1, 74, 7),
+                    Ipv4Address::new(163, 1, 74, 3),
                 ])
                 .unwrap()
             )
@@ -1295,9 +1295,9 @@ mod test {
             repr.dns_servers,
             Some(
                 Vec::from_slice(&[
-                    Ipv4Address([163, 1, 74, 6]),
-                    Ipv4Address([163, 1, 74, 7]),
-                    Ipv4Address([163, 1, 74, 3])
+                    Ipv4Address::new(163, 1, 74, 6),
+                    Ipv4Address::new(163, 1, 74, 7),
+                    Ipv4Address::new(163, 1, 74, 3)
                 ])
                 .unwrap()
             )

+ 2 - 2
src/wire/dns.rs

@@ -7,9 +7,9 @@ use core::iter::Iterator;
 
 use super::{Error, Result};
 #[cfg(feature = "proto-ipv4")]
-use crate::wire::Ipv4Address;
+use crate::wire::{Ipv4Address, Ipv4AddressExt};
 #[cfg(feature = "proto-ipv6")]
-use crate::wire::Ipv6Address;
+use crate::wire::{Ipv6Address, Ipv6AddressExt};
 
 enum_with_unknown! {
     /// DNS OpCodes

+ 8 - 16
src/wire/icmpv6.rs

@@ -847,10 +847,8 @@ mod test {
     use super::*;
     use crate::wire::{IpProtocol, Ipv6Address, Ipv6Repr};
 
-    const MOCK_IP_ADDR_1: Ipv6Address =
-        Ipv6Address([0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]);
-    const MOCK_IP_ADDR_2: Ipv6Address =
-        Ipv6Address([0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2]);
+    const MOCK_IP_ADDR_1: Ipv6Address = Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 1);
+    const MOCK_IP_ADDR_2: Ipv6Address = Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 2);
 
     static ECHO_PACKET_BYTES: [u8; 12] = [
         0x80, 0x00, 0x19, 0xb3, 0x12, 0x34, 0xab, 0xcd, 0xaa, 0x00, 0x00, 0xff,
@@ -888,14 +886,8 @@ mod test {
         Repr::PktTooBig {
             mtu: 1500,
             header: Ipv6Repr {
-                src_addr: Ipv6Address([
-                    0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                    0x00, 0x00, 0x01,
-                ]),
-                dst_addr: Ipv6Address([
-                    0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                    0x00, 0x00, 0x02,
-                ]),
+                src_addr: Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 1),
+                dst_addr: Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 2),
                 next_header: IpProtocol::Udp,
                 payload_len: 12,
                 hop_limit: 0x40,
@@ -1017,8 +1009,8 @@ mod test {
         let repr = Repr::PktTooBig {
             mtu: 1280,
             header: Ipv6Repr {
-                src_addr: Default::default(),
-                dst_addr: Default::default(),
+                src_addr: Ipv6Address::UNSPECIFIED,
+                dst_addr: Ipv6Address::UNSPECIFIED,
                 next_header: IpProtocol::Tcp,
                 hop_limit: 64,
                 payload_len: 1280,
@@ -1031,8 +1023,8 @@ mod test {
     #[test]
     fn test_mtu_truncated_payload_roundtrip() {
         let ip_packet_repr = Ipv6Repr {
-            src_addr: Default::default(),
-            dst_addr: Default::default(),
+            src_addr: Ipv6Address::UNSPECIFIED,
+            dst_addr: Ipv6Address::UNSPECIFIED,
             next_header: IpProtocol::Tcp,
             hop_limit: 64,
             payload_len: IPV6_MIN_MTU - IPV6_HEADER_LEN,

+ 1 - 1
src/wire/ieee802154.rs

@@ -3,7 +3,7 @@ use core::fmt;
 use byteorder::{ByteOrder, LittleEndian};
 
 use super::{Error, Result};
-use crate::wire::ipv6::Address as Ipv6Address;
+use crate::wire::{Ipv6Address, Ipv6AddressExt};
 
 enum_with_unknown! {
     /// IEEE 802.15.4 frame type.

+ 2 - 2
src/wire/igmp.rs

@@ -5,7 +5,7 @@ use super::{Error, Result};
 use crate::time::Duration;
 use crate::wire::ip::checksum;
 
-use crate::wire::Ipv4Address;
+use crate::wire::{Ipv4Address, Ipv4AddressExt};
 
 enum_with_unknown! {
     /// Internet Group Management Protocol v1/v2 message version/type.
@@ -156,7 +156,7 @@ impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
     #[inline]
     pub fn set_group_address(&mut self, addr: Ipv4Address) {
         let data = self.buffer.as_mut();
-        data[field::GROUP_ADDRESS].copy_from_slice(addr.as_bytes());
+        data[field::GROUP_ADDRESS].copy_from_slice(&addr.octets());
     }
 
     /// Compute and fill in the header checksum.

+ 19 - 58
src/wire/ip.rs

@@ -4,9 +4,9 @@ use core::fmt;
 use super::{Error, Result};
 use crate::phy::ChecksumCapabilities;
 #[cfg(feature = "proto-ipv4")]
-use crate::wire::{Ipv4Address, Ipv4Cidr, Ipv4Packet, Ipv4Repr};
+use crate::wire::{Ipv4Address, Ipv4AddressExt, Ipv4Cidr, Ipv4Packet, Ipv4Repr};
 #[cfg(feature = "proto-ipv6")]
-use crate::wire::{Ipv6Address, Ipv6Cidr, Ipv6Packet, Ipv6Repr};
+use crate::wire::{Ipv6Address, Ipv6AddressExt, Ipv6Cidr, Ipv6Packet, Ipv6Repr};
 
 /// Internet protocol version.
 #[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
@@ -127,23 +127,13 @@ impl Address {
         }
     }
 
-    /// Return an address as a sequence of octets, in big-endian.
-    pub const fn as_bytes(&self) -> &[u8] {
-        match self {
-            #[cfg(feature = "proto-ipv4")]
-            Address::Ipv4(addr) => addr.as_bytes(),
-            #[cfg(feature = "proto-ipv6")]
-            Address::Ipv6(addr) => addr.as_bytes(),
-        }
-    }
-
     /// Query whether the address is a valid unicast address.
     pub fn is_unicast(&self) -> bool {
         match self {
             #[cfg(feature = "proto-ipv4")]
-            Address::Ipv4(addr) => addr.is_unicast(),
+            Address::Ipv4(addr) => addr.x_is_unicast(),
             #[cfg(feature = "proto-ipv6")]
-            Address::Ipv6(addr) => addr.is_unicast(),
+            Address::Ipv6(addr) => addr.x_is_unicast(),
         }
     }
 
@@ -180,27 +170,12 @@ impl Address {
     /// If `self` is a CIDR-compatible subnet mask, return `Some(prefix_len)`,
     /// where `prefix_len` is the number of leading zeroes. Return `None` otherwise.
     pub fn prefix_len(&self) -> Option<u8> {
-        let mut ones = true;
-        let mut prefix_len = 0;
-        for byte in self.as_bytes() {
-            let mut mask = 0x80;
-            for _ in 0..8 {
-                let one = *byte & mask != 0;
-                if ones {
-                    // Expect 1s until first 0
-                    if one {
-                        prefix_len += 1;
-                    } else {
-                        ones = false;
-                    }
-                } else if one {
-                    // 1 where 0 was expected
-                    return None;
-                }
-                mask >>= 1;
-            }
+        match self {
+            #[cfg(feature = "proto-ipv4")]
+            Address::Ipv4(addr) => addr.prefix_len(),
+            #[cfg(feature = "proto-ipv6")]
+            Address::Ipv6(addr) => addr.prefix_len(),
         }
-        Some(prefix_len)
     }
 }
 
@@ -208,8 +183,8 @@ impl Address {
 impl From<::core::net::IpAddr> for Address {
     fn from(x: ::core::net::IpAddr) -> Address {
         match x {
-            ::core::net::IpAddr::V4(ipv4) => Address::Ipv4(ipv4.into()),
-            ::core::net::IpAddr::V6(ipv6) => Address::Ipv6(ipv6.into()),
+            ::core::net::IpAddr::V4(ipv4) => Address::Ipv4(ipv4),
+            ::core::net::IpAddr::V6(ipv6) => Address::Ipv6(ipv6),
         }
     }
 }
@@ -218,31 +193,17 @@ impl From<Address> for ::core::net::IpAddr {
     fn from(x: Address) -> ::core::net::IpAddr {
         match x {
             #[cfg(feature = "proto-ipv4")]
-            Address::Ipv4(ipv4) => ::core::net::IpAddr::V4(ipv4.into()),
+            Address::Ipv4(ipv4) => ::core::net::IpAddr::V4(ipv4),
             #[cfg(feature = "proto-ipv6")]
-            Address::Ipv6(ipv6) => ::core::net::IpAddr::V6(ipv6.into()),
+            Address::Ipv6(ipv6) => ::core::net::IpAddr::V6(ipv6),
         }
     }
 }
 
-#[cfg(feature = "proto-ipv4")]
-impl From<::core::net::Ipv4Addr> for Address {
-    fn from(ipv4: ::core::net::Ipv4Addr) -> Address {
-        Address::Ipv4(ipv4.into())
-    }
-}
-
-#[cfg(feature = "proto-ipv6")]
-impl From<::core::net::Ipv6Addr> for Address {
-    fn from(ipv6: ::core::net::Ipv6Addr) -> Address {
-        Address::Ipv6(ipv6.into())
-    }
-}
-
 #[cfg(feature = "proto-ipv4")]
 impl From<Ipv4Address> for Address {
-    fn from(addr: Ipv4Address) -> Self {
-        Address::Ipv4(addr)
+    fn from(ipv4: Ipv4Address) -> Address {
+        Address::Ipv4(ipv4)
     }
 }
 
@@ -773,8 +734,8 @@ pub mod checksum {
         NetworkEndian::write_u16(&mut proto_len[2..4], length as u16);
 
         combine(&[
-            data(src_addr.as_bytes()),
-            data(dst_addr.as_bytes()),
+            data(&src_addr.octets()),
+            data(&dst_addr.octets()),
             data(&proto_len[..]),
         ])
     }
@@ -791,8 +752,8 @@ pub mod checksum {
         NetworkEndian::write_u16(&mut proto_len[2..4], length as u16);
 
         combine(&[
-            data(src_addr.as_bytes()),
-            data(dst_addr.as_bytes()),
+            data(&src_addr.octets()),
+            data(&dst_addr.octets()),
             data(&proto_len[..]),
         ])
     }

+ 148 - 211
src/wire/ipv4.rs

@@ -26,6 +26,12 @@ pub const MIN_MTU: usize = 576;
 /// [RFC 8200 § 2]: https://www.rfc-editor.org/rfc/rfc791#section-3.2
 pub const ADDR_SIZE: usize = 4;
 
+/// All multicast-capable nodes
+pub const MULTICAST_ALL_SYSTEMS: Address = Address::new(224, 0, 0, 1);
+
+/// All multicast-capable routers
+pub const MULTICAST_ALL_ROUTERS: Address = Address::new(224, 0, 0, 2);
+
 #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Clone, Copy)]
 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
 pub struct Key {
@@ -35,117 +41,65 @@ pub struct Key {
     protocol: Protocol,
 }
 
-/// A four-octet IPv4 address.
-#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default)]
-pub struct Address(pub [u8; ADDR_SIZE]);
-
-impl Address {
-    /// An unspecified address.
-    pub const UNSPECIFIED: Address = Address([0x00; ADDR_SIZE]);
-
-    /// The broadcast address.
-    pub const BROADCAST: Address = Address([0xff; ADDR_SIZE]);
-
-    /// All multicast-capable nodes
-    pub const MULTICAST_ALL_SYSTEMS: Address = Address([224, 0, 0, 1]);
-
-    /// All multicast-capable routers
-    pub const MULTICAST_ALL_ROUTERS: Address = Address([224, 0, 0, 2]);
-
-    /// Construct an IPv4 address from parts.
-    pub const fn new(a0: u8, a1: u8, a2: u8, a3: u8) -> Address {
-        Address([a0, a1, a2, a3])
-    }
+pub use core::net::Ipv4Addr as Address;
 
+pub(crate) trait AddressExt {
     /// Construct an IPv4 address from a sequence of octets, in big-endian.
     ///
     /// # Panics
     /// The function panics if `data` is not four octets long.
-    pub fn from_bytes(data: &[u8]) -> Address {
-        let mut bytes = [0; ADDR_SIZE];
-        bytes.copy_from_slice(data);
-        Address(bytes)
-    }
-
-    /// Return an IPv4 address as a sequence of octets, in big-endian.
-    pub const fn as_bytes(&self) -> &[u8] {
-        &self.0
-    }
+    fn from_bytes(data: &[u8]) -> Self;
 
     /// Query whether the address is an unicast address.
-    pub fn is_unicast(&self) -> bool {
-        !(self.is_broadcast() || self.is_multicast() || self.is_unspecified())
-    }
-
-    /// Query whether the address is the broadcast address.
-    pub fn is_broadcast(&self) -> bool {
-        self.0[0..4] == [255; ADDR_SIZE]
-    }
-
-    /// Query whether the address is a multicast address.
-    pub const fn is_multicast(&self) -> bool {
-        self.0[0] & 0xf0 == 224
-    }
-
-    /// Query whether the address falls into the "unspecified" range.
-    pub const fn is_unspecified(&self) -> bool {
-        self.0[0] == 0
-    }
-
-    /// Query whether the address falls into the "link-local" range.
-    pub fn is_link_local(&self) -> bool {
-        self.0[0..2] == [169, 254]
-    }
-
-    /// Query whether the address falls into the "loopback" range.
-    pub const fn is_loopback(&self) -> bool {
-        self.0[0] == 127
-    }
-
-    /// Convert to an `IpAddress`.
     ///
-    /// Same as `.into()`, but works in `const`.
-    pub const fn into_address(self) -> super::IpAddress {
-        super::IpAddress::Ipv4(self)
-    }
-}
+    /// `x_` prefix is to avoid a collision with the still-unstable method in `core::ip`.
+    fn x_is_unicast(&self) -> bool;
 
-impl From<::core::net::Ipv4Addr> for Address {
-    fn from(x: ::core::net::Ipv4Addr) -> Address {
-        Address(x.octets())
-    }
+    /// If `self` is a CIDR-compatible subnet mask, return `Some(prefix_len)`,
+    /// where `prefix_len` is the number of leading zeroes. Return `None` otherwise.
+    fn prefix_len(&self) -> Option<u8>;
 }
 
-impl From<Address> for ::core::net::Ipv4Addr {
-    fn from(Address(x): Address) -> ::core::net::Ipv4Addr {
-        x.into()
+impl AddressExt for Address {
+    fn from_bytes(data: &[u8]) -> Address {
+        let mut bytes = [0; ADDR_SIZE];
+        bytes.copy_from_slice(data);
+        Address::from_bits(u32::from_be_bytes(bytes))
     }
-}
 
-impl fmt::Display for Address {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        let bytes = self.0;
-        write!(f, "{}.{}.{}.{}", bytes[0], bytes[1], bytes[2], bytes[3])
+    /// Query whether the address is an unicast address.
+    fn x_is_unicast(&self) -> bool {
+        !(self.is_broadcast() || self.is_multicast() || self.is_unspecified())
     }
-}
 
-#[cfg(feature = "defmt")]
-impl defmt::Format for Address {
-    fn format(&self, f: defmt::Formatter) {
-        defmt::write!(
-            f,
-            "{=u8}.{=u8}.{=u8}.{=u8}",
-            self.0[0],
-            self.0[1],
-            self.0[2],
-            self.0[3]
-        )
+    fn prefix_len(&self) -> Option<u8> {
+        let mut ones = true;
+        let mut prefix_len = 0;
+        for byte in self.octets() {
+            let mut mask = 0x80;
+            for _ in 0..8 {
+                let one = byte & mask != 0;
+                if ones {
+                    // Expect 1s until first 0
+                    if one {
+                        prefix_len += 1;
+                    } else {
+                        ones = false;
+                    }
+                } else if one {
+                    // 1 where 0 was expected
+                    return None;
+                }
+                mask >>= 1;
+            }
+        }
+        Some(prefix_len)
     }
 }
 
 /// A specification of an IPv4 CIDR block, containing an address and a variable-length
 /// subnet masking prefix length.
-#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default)]
+#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
 pub struct Cidr {
     address: Address,
     prefix_len: u8,
@@ -166,7 +120,7 @@ impl Cidr {
 
     /// Create an IPv4 CIDR block from the given address and network mask.
     pub fn from_netmask(addr: Address, netmask: Address) -> Result<Cidr> {
-        let netmask = NetworkEndian::read_u32(&netmask.0[..]);
+        let netmask = netmask.to_bits();
         if netmask.leading_zeros() == 0 && netmask.trailing_zeros() == netmask.count_zeros() {
             Ok(Cidr {
                 address: addr,
@@ -190,18 +144,11 @@ impl Cidr {
     /// Return the network mask of this IPv4 CIDR.
     pub const fn netmask(&self) -> Address {
         if self.prefix_len == 0 {
-            return Address([0, 0, 0, 0]);
+            return Address::new(0, 0, 0, 0);
         }
 
         let number = 0xffffffffu32 << (32 - self.prefix_len);
-        let data = [
-            ((number >> 24) & 0xff) as u8,
-            ((number >> 16) & 0xff) as u8,
-            ((number >> 8) & 0xff) as u8,
-            ((number >> 0) & 0xff) as u8,
-        ];
-
-        Address(data)
+        Address::from_bits(number)
     }
 
     /// Return the broadcast address of this IPv4 CIDR.
@@ -212,29 +159,15 @@ impl Cidr {
             return None;
         }
 
-        let network_number = NetworkEndian::read_u32(&network.address.0[..]);
+        let network_number = network.address.to_bits();
         let number = network_number | 0xffffffffu32 >> network.prefix_len;
-        let data = [
-            ((number >> 24) & 0xff) as u8,
-            ((number >> 16) & 0xff) as u8,
-            ((number >> 8) & 0xff) as u8,
-            ((number >> 0) & 0xff) as u8,
-        ];
-
-        Some(Address(data))
+        Some(Address::from_bits(number))
     }
 
     /// Return the network block of this IPv4 CIDR.
     pub const fn network(&self) -> Cidr {
-        let mask = self.netmask().0;
-        let network = [
-            self.address.0[0] & mask[0],
-            self.address.0[1] & mask[1],
-            self.address.0[2] & mask[2],
-            self.address.0[3] & mask[3],
-        ];
         Cidr {
-            address: Address(network),
+            address: Address::from_bits(self.address.to_bits() & self.netmask().to_bits()),
             prefix_len: self.prefix_len,
         }
     }
@@ -242,15 +175,8 @@ impl Cidr {
     /// Query whether the subnetwork described by this IPv4 CIDR block contains
     /// the given address.
     pub fn contains_addr(&self, addr: &Address) -> bool {
-        // right shift by 32 is not legal
-        if self.prefix_len == 0 {
-            return true;
-        }
-
-        let shift = 32 - self.prefix_len;
-        let self_prefix = NetworkEndian::read_u32(self.address.as_bytes()) >> shift;
-        let addr_prefix = NetworkEndian::read_u32(addr.as_bytes()) >> shift;
-        self_prefix == addr_prefix
+        self.address.to_bits() & self.netmask().to_bits()
+            == addr.to_bits() & self.netmask().to_bits()
     }
 
     /// Query whether the subnetwork described by this IPv4 CIDR block contains
@@ -576,14 +502,14 @@ impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
     #[inline]
     pub fn set_src_addr(&mut self, value: Address) {
         let data = self.buffer.as_mut();
-        data[field::SRC_ADDR].copy_from_slice(value.as_bytes())
+        data[field::SRC_ADDR].copy_from_slice(&value.octets())
     }
 
     /// Set the destination address field.
     #[inline]
     pub fn set_dst_addr(&mut self, value: Address) {
         let data = self.buffer.as_mut();
-        data[field::DST_ADDR].copy_from_slice(value.as_bytes())
+        data[field::DST_ADDR].copy_from_slice(&value.octets())
     }
 
     /// Compute and fill in the header checksum.
@@ -795,13 +721,13 @@ pub(crate) mod test {
     use super::*;
 
     #[allow(unused)]
-    pub(crate) const MOCK_IP_ADDR_1: Address = Address([192, 168, 1, 1]);
+    pub(crate) const MOCK_IP_ADDR_1: Address = Address::new(192, 168, 1, 1);
     #[allow(unused)]
-    pub(crate) const MOCK_IP_ADDR_2: Address = Address([192, 168, 1, 2]);
+    pub(crate) const MOCK_IP_ADDR_2: Address = Address::new(192, 168, 1, 2);
     #[allow(unused)]
-    pub(crate) const MOCK_IP_ADDR_3: Address = Address([192, 168, 1, 3]);
+    pub(crate) const MOCK_IP_ADDR_3: Address = Address::new(192, 168, 1, 3);
     #[allow(unused)]
-    pub(crate) const MOCK_IP_ADDR_4: Address = Address([192, 168, 1, 4]);
+    pub(crate) const MOCK_IP_ADDR_4: Address = Address::new(192, 168, 1, 4);
     #[allow(unused)]
     pub(crate) const MOCK_UNSPECIFIED: Address = Address::UNSPECIFIED;
 
@@ -827,8 +753,8 @@ pub(crate) mod test {
         assert_eq!(packet.hop_limit(), 0x1a);
         assert_eq!(packet.next_header(), Protocol::Icmp);
         assert_eq!(packet.checksum(), 0xd56e);
-        assert_eq!(packet.src_addr(), Address([0x11, 0x12, 0x13, 0x14]));
-        assert_eq!(packet.dst_addr(), Address([0x21, 0x22, 0x23, 0x24]));
+        assert_eq!(packet.src_addr(), Address::new(0x11, 0x12, 0x13, 0x14));
+        assert_eq!(packet.dst_addr(), Address::new(0x21, 0x22, 0x23, 0x24));
         assert!(packet.verify_checksum());
         assert_eq!(packet.payload(), &PAYLOAD_BYTES[..]);
     }
@@ -849,8 +775,8 @@ pub(crate) mod test {
         packet.set_frag_offset(0x203 * 8);
         packet.set_hop_limit(0x1a);
         packet.set_next_header(Protocol::Icmp);
-        packet.set_src_addr(Address([0x11, 0x12, 0x13, 0x14]));
-        packet.set_dst_addr(Address([0x21, 0x22, 0x23, 0x24]));
+        packet.set_src_addr(Address::new(0x11, 0x12, 0x13, 0x14));
+        packet.set_dst_addr(Address::new(0x21, 0x22, 0x23, 0x24));
         packet.fill_checksum();
         packet.payload_mut().copy_from_slice(&PAYLOAD_BYTES[..]);
         assert_eq!(&*packet.into_inner(), &PACKET_BYTES[..]);
@@ -890,8 +816,8 @@ pub(crate) mod test {
 
     const fn packet_repr() -> Repr {
         Repr {
-            src_addr: Address([0x11, 0x12, 0x13, 0x14]),
-            dst_addr: Address([0x21, 0x22, 0x23, 0x24]),
+            src_addr: Address::new(0x11, 0x12, 0x13, 0x14),
+            dst_addr: Address::new(0x21, 0x22, 0x23, 0x24),
             next_header: Protocol::Icmp,
             payload_len: 4,
             hop_limit: 64,
@@ -1017,124 +943,135 @@ pub(crate) mod test {
 
     #[test]
     fn test_cidr_from_netmask() {
-        assert!(Cidr::from_netmask(Address([0, 0, 0, 0]), Address([1, 0, 2, 0])).is_err());
-        assert!(Cidr::from_netmask(Address([0, 0, 0, 0]), Address([0, 0, 0, 0])).is_err());
+        assert!(Cidr::from_netmask(Address::new(0, 0, 0, 0), Address::new(1, 0, 2, 0)).is_err());
+        assert!(Cidr::from_netmask(Address::new(0, 0, 0, 0), Address::new(0, 0, 0, 0)).is_err());
         assert_eq!(
-            Cidr::from_netmask(Address([0, 0, 0, 1]), Address([255, 255, 255, 0])).unwrap(),
-            Cidr::new(Address([0, 0, 0, 1]), 24)
+            Cidr::from_netmask(Address::new(0, 0, 0, 1), Address::new(255, 255, 255, 0)).unwrap(),
+            Cidr::new(Address::new(0, 0, 0, 1), 24)
         );
         assert_eq!(
-            Cidr::from_netmask(Address([192, 168, 0, 1]), Address([255, 255, 0, 0])).unwrap(),
-            Cidr::new(Address([192, 168, 0, 1]), 16)
+            Cidr::from_netmask(Address::new(192, 168, 0, 1), Address::new(255, 255, 0, 0)).unwrap(),
+            Cidr::new(Address::new(192, 168, 0, 1), 16)
         );
         assert_eq!(
-            Cidr::from_netmask(Address([172, 16, 0, 1]), Address([255, 240, 0, 0])).unwrap(),
-            Cidr::new(Address([172, 16, 0, 1]), 12)
+            Cidr::from_netmask(Address::new(172, 16, 0, 1), Address::new(255, 240, 0, 0)).unwrap(),
+            Cidr::new(Address::new(172, 16, 0, 1), 12)
         );
         assert_eq!(
-            Cidr::from_netmask(Address([255, 255, 255, 1]), Address([255, 255, 255, 0])).unwrap(),
-            Cidr::new(Address([255, 255, 255, 1]), 24)
+            Cidr::from_netmask(
+                Address::new(255, 255, 255, 1),
+                Address::new(255, 255, 255, 0)
+            )
+            .unwrap(),
+            Cidr::new(Address::new(255, 255, 255, 1), 24)
         );
         assert_eq!(
-            Cidr::from_netmask(Address([255, 255, 255, 255]), Address([255, 255, 255, 255]))
-                .unwrap(),
-            Cidr::new(Address([255, 255, 255, 255]), 32)
+            Cidr::from_netmask(
+                Address::new(255, 255, 255, 255),
+                Address::new(255, 255, 255, 255)
+            )
+            .unwrap(),
+            Cidr::new(Address::new(255, 255, 255, 255), 32)
         );
     }
 
     #[test]
     fn test_cidr_netmask() {
         assert_eq!(
-            Cidr::new(Address([0, 0, 0, 0]), 0).netmask(),
-            Address([0, 0, 0, 0])
+            Cidr::new(Address::new(0, 0, 0, 0), 0).netmask(),
+            Address::new(0, 0, 0, 0)
         );
         assert_eq!(
-            Cidr::new(Address([0, 0, 0, 1]), 24).netmask(),
-            Address([255, 255, 255, 0])
+            Cidr::new(Address::new(0, 0, 0, 1), 24).netmask(),
+            Address::new(255, 255, 255, 0)
         );
         assert_eq!(
-            Cidr::new(Address([0, 0, 0, 0]), 32).netmask(),
-            Address([255, 255, 255, 255])
+            Cidr::new(Address::new(0, 0, 0, 0), 32).netmask(),
+            Address::new(255, 255, 255, 255)
         );
         assert_eq!(
-            Cidr::new(Address([127, 0, 0, 0]), 8).netmask(),
-            Address([255, 0, 0, 0])
+            Cidr::new(Address::new(127, 0, 0, 0), 8).netmask(),
+            Address::new(255, 0, 0, 0)
         );
         assert_eq!(
-            Cidr::new(Address([192, 168, 0, 0]), 16).netmask(),
-            Address([255, 255, 0, 0])
+            Cidr::new(Address::new(192, 168, 0, 0), 16).netmask(),
+            Address::new(255, 255, 0, 0)
         );
         assert_eq!(
-            Cidr::new(Address([192, 168, 1, 1]), 16).netmask(),
-            Address([255, 255, 0, 0])
+            Cidr::new(Address::new(192, 168, 1, 1), 16).netmask(),
+            Address::new(255, 255, 0, 0)
         );
         assert_eq!(
-            Cidr::new(Address([192, 168, 1, 1]), 17).netmask(),
-            Address([255, 255, 128, 0])
+            Cidr::new(Address::new(192, 168, 1, 1), 17).netmask(),
+            Address::new(255, 255, 128, 0)
         );
         assert_eq!(
-            Cidr::new(Address([172, 16, 0, 0]), 12).netmask(),
-            Address([255, 240, 0, 0])
+            Cidr::new(Address::new(172, 16, 0, 0), 12).netmask(),
+            Address::new(255, 240, 0, 0)
         );
         assert_eq!(
-            Cidr::new(Address([255, 255, 255, 1]), 24).netmask(),
-            Address([255, 255, 255, 0])
+            Cidr::new(Address::new(255, 255, 255, 1), 24).netmask(),
+            Address::new(255, 255, 255, 0)
         );
         assert_eq!(
-            Cidr::new(Address([255, 255, 255, 255]), 32).netmask(),
-            Address([255, 255, 255, 255])
+            Cidr::new(Address::new(255, 255, 255, 255), 32).netmask(),
+            Address::new(255, 255, 255, 255)
         );
     }
 
     #[test]
     fn test_cidr_broadcast() {
         assert_eq!(
-            Cidr::new(Address([0, 0, 0, 0]), 0).broadcast().unwrap(),
-            Address([255, 255, 255, 255])
+            Cidr::new(Address::new(0, 0, 0, 0), 0).broadcast().unwrap(),
+            Address::new(255, 255, 255, 255)
         );
         assert_eq!(
-            Cidr::new(Address([0, 0, 0, 1]), 24).broadcast().unwrap(),
-            Address([0, 0, 0, 255])
+            Cidr::new(Address::new(0, 0, 0, 1), 24).broadcast().unwrap(),
+            Address::new(0, 0, 0, 255)
         );
-        assert_eq!(Cidr::new(Address([0, 0, 0, 0]), 32).broadcast(), None);
+        assert_eq!(Cidr::new(Address::new(0, 0, 0, 0), 32).broadcast(), None);
         assert_eq!(
-            Cidr::new(Address([127, 0, 0, 0]), 8).broadcast().unwrap(),
-            Address([127, 255, 255, 255])
+            Cidr::new(Address::new(127, 0, 0, 0), 8)
+                .broadcast()
+                .unwrap(),
+            Address::new(127, 255, 255, 255)
         );
         assert_eq!(
-            Cidr::new(Address([192, 168, 0, 0]), 16)
+            Cidr::new(Address::new(192, 168, 0, 0), 16)
                 .broadcast()
                 .unwrap(),
-            Address([192, 168, 255, 255])
+            Address::new(192, 168, 255, 255)
         );
         assert_eq!(
-            Cidr::new(Address([192, 168, 1, 1]), 16)
+            Cidr::new(Address::new(192, 168, 1, 1), 16)
                 .broadcast()
                 .unwrap(),
-            Address([192, 168, 255, 255])
+            Address::new(192, 168, 255, 255)
         );
         assert_eq!(
-            Cidr::new(Address([192, 168, 1, 1]), 17)
+            Cidr::new(Address::new(192, 168, 1, 1), 17)
                 .broadcast()
                 .unwrap(),
-            Address([192, 168, 127, 255])
+            Address::new(192, 168, 127, 255)
         );
         assert_eq!(
-            Cidr::new(Address([172, 16, 0, 1]), 12).broadcast().unwrap(),
-            Address([172, 31, 255, 255])
+            Cidr::new(Address::new(172, 16, 0, 1), 12)
+                .broadcast()
+                .unwrap(),
+            Address::new(172, 31, 255, 255)
         );
         assert_eq!(
-            Cidr::new(Address([255, 255, 255, 1]), 24)
+            Cidr::new(Address::new(255, 255, 255, 1), 24)
                 .broadcast()
                 .unwrap(),
-            Address([255, 255, 255, 255])
+            Address::new(255, 255, 255, 255)
         );
         assert_eq!(
-            Cidr::new(Address([255, 255, 255, 254]), 31).broadcast(),
+            Cidr::new(Address::new(255, 255, 255, 254), 31).broadcast(),
             None
         );
         assert_eq!(
-            Cidr::new(Address([255, 255, 255, 255]), 32).broadcast(),
+            Cidr::new(Address::new(255, 255, 255, 255), 32).broadcast(),
             None
         );
     }
@@ -1142,44 +1079,44 @@ pub(crate) mod test {
     #[test]
     fn test_cidr_network() {
         assert_eq!(
-            Cidr::new(Address([0, 0, 0, 0]), 0).network(),
-            Cidr::new(Address([0, 0, 0, 0]), 0)
+            Cidr::new(Address::new(0, 0, 0, 0), 0).network(),
+            Cidr::new(Address::new(0, 0, 0, 0), 0)
         );
         assert_eq!(
-            Cidr::new(Address([0, 0, 0, 1]), 24).network(),
-            Cidr::new(Address([0, 0, 0, 0]), 24)
+            Cidr::new(Address::new(0, 0, 0, 1), 24).network(),
+            Cidr::new(Address::new(0, 0, 0, 0), 24)
         );
         assert_eq!(
-            Cidr::new(Address([0, 0, 0, 0]), 32).network(),
-            Cidr::new(Address([0, 0, 0, 0]), 32)
+            Cidr::new(Address::new(0, 0, 0, 0), 32).network(),
+            Cidr::new(Address::new(0, 0, 0, 0), 32)
         );
         assert_eq!(
-            Cidr::new(Address([127, 0, 0, 0]), 8).network(),
-            Cidr::new(Address([127, 0, 0, 0]), 8)
+            Cidr::new(Address::new(127, 0, 0, 0), 8).network(),
+            Cidr::new(Address::new(127, 0, 0, 0), 8)
         );
         assert_eq!(
-            Cidr::new(Address([192, 168, 0, 0]), 16).network(),
-            Cidr::new(Address([192, 168, 0, 0]), 16)
+            Cidr::new(Address::new(192, 168, 0, 0), 16).network(),
+            Cidr::new(Address::new(192, 168, 0, 0), 16)
         );
         assert_eq!(
-            Cidr::new(Address([192, 168, 1, 1]), 16).network(),
-            Cidr::new(Address([192, 168, 0, 0]), 16)
+            Cidr::new(Address::new(192, 168, 1, 1), 16).network(),
+            Cidr::new(Address::new(192, 168, 0, 0), 16)
         );
         assert_eq!(
-            Cidr::new(Address([192, 168, 1, 1]), 17).network(),
-            Cidr::new(Address([192, 168, 0, 0]), 17)
+            Cidr::new(Address::new(192, 168, 1, 1), 17).network(),
+            Cidr::new(Address::new(192, 168, 0, 0), 17)
         );
         assert_eq!(
-            Cidr::new(Address([172, 16, 0, 1]), 12).network(),
-            Cidr::new(Address([172, 16, 0, 0]), 12)
+            Cidr::new(Address::new(172, 16, 0, 1), 12).network(),
+            Cidr::new(Address::new(172, 16, 0, 0), 12)
         );
         assert_eq!(
-            Cidr::new(Address([255, 255, 255, 1]), 24).network(),
-            Cidr::new(Address([255, 255, 255, 0]), 24)
+            Cidr::new(Address::new(255, 255, 255, 1), 24).network(),
+            Cidr::new(Address::new(255, 255, 255, 0), 24)
         );
         assert_eq!(
-            Cidr::new(Address([255, 255, 255, 255]), 32).network(),
-            Cidr::new(Address([255, 255, 255, 255]), 32)
+            Cidr::new(Address::new(255, 255, 255, 255), 32).network(),
+            Cidr::new(Address::new(255, 255, 255, 255), 32)
         );
     }
 }

+ 155 - 518
src/wire/ipv6.rs

@@ -5,8 +5,6 @@ use core::fmt;
 
 use super::{Error, Result};
 use crate::wire::ip::pretty_print_ip_payload;
-#[cfg(feature = "proto-ipv4")]
-use crate::wire::ipv4;
 
 pub use super::IpProtocol as Protocol;
 
@@ -20,10 +18,25 @@ pub const MIN_MTU: usize = 1280;
 /// [RFC 8200 § 2]: https://www.rfc-editor.org/rfc/rfc4291#section-2
 pub const ADDR_SIZE: usize = 16;
 
-/// Size of IPv4-mapping prefix in octets.
+/// The link-local [all nodes multicast address].
 ///
-/// [RFC 8200 § 2]: https://www.rfc-editor.org/rfc/rfc4291#section-2
-pub const IPV4_MAPPED_PREFIX_SIZE: usize = ADDR_SIZE - 4; // 4 == ipv4::ADDR_SIZE , cannot DRY here because of dependency on a IPv4 module which is behind the feature
+/// [all nodes multicast address]: https://tools.ietf.org/html/rfc4291#section-2.7.1
+pub const LINK_LOCAL_ALL_NODES: Address = Address::new(0xff02, 0, 0, 0, 0, 0, 0, 1);
+
+/// The link-local [all routers multicast address].
+///
+/// [all routers multicast address]: https://tools.ietf.org/html/rfc4291#section-2.7.1
+pub const LINK_LOCAL_ALL_ROUTERS: Address = Address::new(0xff02, 0, 0, 0, 0, 0, 0, 2);
+
+/// The link-local [all MLVDv2-capable routers multicast address].
+///
+/// [all MLVDv2-capable routers multicast address]: https://tools.ietf.org/html/rfc3810#section-11
+pub const LINK_LOCAL_ALL_MLDV2_ROUTERS: Address = Address::new(0xff02, 0, 0, 0, 0, 0, 0, 0x16);
+
+/// The link-local [all RPL nodes multicast address].
+///
+/// [all RPL nodes multicast address]: https://www.rfc-editor.org/rfc/rfc6550.html#section-20.19
+pub const LINK_LOCAL_ALL_RPL_NODES: Address = Address::new(0xff02, 0, 0, 0, 0, 0, 0, 0x1a);
 
 /// The [scope] of an address.
 ///
@@ -61,211 +74,92 @@ impl From<u8> for MulticastScope {
     }
 }
 
-/// A sixteen-octet IPv6 address.
-#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default)]
-pub struct Address(pub [u8; ADDR_SIZE]);
-
-impl Address {
-    /// The [unspecified address].
-    ///
-    /// [unspecified address]: https://tools.ietf.org/html/rfc4291#section-2.5.2
-    pub const UNSPECIFIED: Address = Address([0x00; ADDR_SIZE]);
+pub use core::net::Ipv6Addr as Address;
 
-    /// The link-local [all nodes multicast address].
+pub(crate) trait AddressExt {
+    /// Construct an IPv6 address from a sequence of octets, in big-endian.
     ///
-    /// [all nodes multicast address]: https://tools.ietf.org/html/rfc4291#section-2.7.1
-    pub const LINK_LOCAL_ALL_NODES: Address = Address([
-        0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x01,
-    ]);
+    /// # Panics
+    /// The function panics if `data` is not sixteen octets long.
+    fn from_bytes(data: &[u8]) -> Address;
 
-    /// The link-local [all routers multicast address].
+    /// Query whether the IPv6 address is an [unicast address].
     ///
-    /// [all routers multicast address]: https://tools.ietf.org/html/rfc4291#section-2.7.1
-    pub const LINK_LOCAL_ALL_ROUTERS: Address = Address([
-        0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x02,
-    ]);
-
-    /// The link-local [all MLVDv2-capable routers multicast address].
+    /// [unicast address]: https://tools.ietf.org/html/rfc4291#section-2.5
     ///
-    /// [all MLVDv2-capable routers multicast address]: https://tools.ietf.org/html/rfc3810#section-11
-    pub const LINK_LOCAL_ALL_MLDV2_ROUTERS: Address = Address([
-        0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x16,
-    ]);
+    /// `x_` prefix is to avoid a collision with the still-unstable method in `core::ip`.
+    fn x_is_unicast(&self) -> bool;
 
-    /// The link-local [all RPL nodes multicast address].
+    /// Query whether the IPv6 address is a [global unicast address].
     ///
-    /// [all RPL nodes multicast address]: https://www.rfc-editor.org/rfc/rfc6550.html#section-20.19
-    pub const LINK_LOCAL_ALL_RPL_NODES: Address = Address([
-        0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x1a,
-    ]);
+    /// [global unicast address]: https://datatracker.ietf.org/doc/html/rfc3587
+    fn is_global_unicast(&self) -> bool;
 
-    /// The [loopback address].
+    /// Query whether the IPv6 address is in the [link-local] scope.
     ///
-    /// [loopback address]: https://tools.ietf.org/html/rfc4291#section-2.5.3
-    pub const LOOPBACK: Address = Address([
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x01,
-    ]);
+    /// [link-local]: https://tools.ietf.org/html/rfc4291#section-2.5.6
+    fn is_link_local(&self) -> bool;
 
-    /// The prefix used in [IPv4-mapped addresses].
+    /// Query whether the IPv6 address is a [Unique Local Address] (ULA).
     ///
-    /// [IPv4-mapped addresses]: https://www.rfc-editor.org/rfc/rfc4291#section-2.5.5.2
-    pub const IPV4_MAPPED_PREFIX: [u8; IPV4_MAPPED_PREFIX_SIZE] =
-        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff];
-
-    /// Construct an IPv6 address from parts.
-    #[allow(clippy::too_many_arguments)]
-    pub const fn new(
-        a0: u16,
-        a1: u16,
-        a2: u16,
-        a3: u16,
-        a4: u16,
-        a5: u16,
-        a6: u16,
-        a7: u16,
-    ) -> Address {
-        Address([
-            (a0 >> 8) as u8,
-            a0 as u8,
-            (a1 >> 8) as u8,
-            a1 as u8,
-            (a2 >> 8) as u8,
-            a2 as u8,
-            (a3 >> 8) as u8,
-            a3 as u8,
-            (a4 >> 8) as u8,
-            a4 as u8,
-            (a5 >> 8) as u8,
-            a5 as u8,
-            (a6 >> 8) as u8,
-            a6 as u8,
-            (a7 >> 8) as u8,
-            a7 as u8,
-        ])
-    }
-
-    /// Construct an IPv6 address from a sequence of octets, in big-endian.
+    /// [Unique Local Address]: https://tools.ietf.org/html/rfc4193
     ///
-    /// # Panics
-    /// The function panics if `data` is not sixteen octets long.
-    pub fn from_bytes(data: &[u8]) -> Address {
-        let mut bytes = [0; ADDR_SIZE];
-        bytes.copy_from_slice(data);
-        Address(bytes)
-    }
+    /// `x_` prefix is to avoid a collision with the still-unstable method in `core::ip`.
+    fn x_is_unique_local(&self) -> bool;
 
-    /// Construct an IPv6 address from a sequence of words, in big-endian.
+    /// Helper function used to mask an address given a prefix.
     ///
     /// # Panics
-    /// The function panics if `data` is not 8 words long.
-    pub fn from_parts(data: &[u16]) -> Address {
-        assert!(data.len() >= 8);
-        let mut bytes = [0; ADDR_SIZE];
-        for (word_idx, chunk) in bytes.chunks_mut(2).enumerate() {
-            NetworkEndian::write_u16(chunk, data[word_idx]);
-        }
-        Address(bytes)
-    }
+    /// This function panics if `mask` is greater than 128.
+    fn mask(&self, mask: u8) -> [u8; ADDR_SIZE];
 
-    /// Write a IPv6 address to the given slice.
+    /// The solicited node for the given unicast address.
     ///
     /// # Panics
-    /// The function panics if `data` is not 8 words long.
-    pub fn write_parts(&self, data: &mut [u16]) {
-        assert!(data.len() >= 8);
-        for (i, chunk) in self.0.chunks(2).enumerate() {
-            data[i] = NetworkEndian::read_u16(chunk);
-        }
-    }
-
-    /// Return an IPv6 address as a sequence of octets, in big-endian.
-    pub const fn as_bytes(&self) -> &[u8] {
-        &self.0
-    }
-
-    /// Query whether the IPv6 address is an [unicast address].
-    ///
-    /// [unicast address]: https://tools.ietf.org/html/rfc4291#section-2.5
-    pub fn is_unicast(&self) -> bool {
-        !(self.is_multicast() || self.is_unspecified())
-    }
+    /// This function panics if the given address is not
+    /// unicast.
+    fn solicited_node(&self) -> Address;
 
-    /// Query whether the IPv6 address is a [global unicast address].
+    /// Return the scope of the address.
     ///
-    /// [global unicast address]: https://datatracker.ietf.org/doc/html/rfc3587
-    pub const fn is_global_unicast(&self) -> bool {
-        (self.0[0] >> 5) == 0b001
-    }
+    /// `x_` prefix is to avoid a collision with the still-unstable method in `core::ip`.
+    fn x_multicast_scope(&self) -> MulticastScope;
 
-    /// Query whether the IPv6 address is a [multicast address].
-    ///
-    /// [multicast address]: https://tools.ietf.org/html/rfc4291#section-2.7
-    pub const fn is_multicast(&self) -> bool {
-        self.0[0] == 0xff
-    }
+    /// If `self` is a CIDR-compatible subnet mask, return `Some(prefix_len)`,
+    /// where `prefix_len` is the number of leading zeroes. Return `None` otherwise.
+    fn prefix_len(&self) -> Option<u8>;
+}
 
-    /// Query whether the IPv6 address is the [unspecified address].
-    ///
-    /// [unspecified address]: https://tools.ietf.org/html/rfc4291#section-2.5.2
-    pub fn is_unspecified(&self) -> bool {
-        self.0 == [0x00; ADDR_SIZE]
+impl AddressExt for Address {
+    fn from_bytes(data: &[u8]) -> Address {
+        let mut bytes = [0; ADDR_SIZE];
+        bytes.copy_from_slice(data);
+        Address::from(bytes)
     }
 
-    /// Query whether the IPv6 address is in the [link-local] scope.
-    ///
-    /// [link-local]: https://tools.ietf.org/html/rfc4291#section-2.5.6
-    pub fn is_link_local(&self) -> bool {
-        self.0[0..8] == [0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
+    fn x_is_unicast(&self) -> bool {
+        !(self.is_multicast() || self.is_unspecified())
     }
 
-    /// Query whether the IPv6 address is a [Unique Local Address] (ULA).
-    ///
-    /// [Unique Local Address]: https://tools.ietf.org/html/rfc4193
-    pub fn is_unique_local(&self) -> bool {
-        (self.0[0] & 0b1111_1110) == 0xfc
+    fn is_global_unicast(&self) -> bool {
+        (self.octets()[0] >> 5) == 0b001
     }
 
-    /// Query whether the IPv6 address is the [loopback address].
-    ///
-    /// [loopback address]: https://tools.ietf.org/html/rfc4291#section-2.5.3
-    pub fn is_loopback(&self) -> bool {
-        *self == Self::LOOPBACK
+    fn is_link_local(&self) -> bool {
+        self.octets()[0..8] == [0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
     }
 
-    /// Query whether the IPv6 address is an [IPv4 mapped IPv6 address].
-    ///
-    /// [IPv4 mapped IPv6 address]: https://tools.ietf.org/html/rfc4291#section-2.5.5.2
-    pub fn is_ipv4_mapped(&self) -> bool {
-        self.0[..IPV4_MAPPED_PREFIX_SIZE] == Self::IPV4_MAPPED_PREFIX
-    }
-
-    #[cfg(feature = "proto-ipv4")]
-    /// Convert an IPv4 mapped IPv6 address to an IPv4 address.
-    pub fn as_ipv4(&self) -> Option<ipv4::Address> {
-        if self.is_ipv4_mapped() {
-            Some(ipv4::Address::from_bytes(
-                &self.0[IPV4_MAPPED_PREFIX_SIZE..],
-            ))
-        } else {
-            None
-        }
+    fn x_is_unique_local(&self) -> bool {
+        (self.octets()[0] & 0b1111_1110) == 0xfc
     }
 
-    /// Helper function used to mask an address given a prefix.
-    ///
-    /// # Panics
-    /// This function panics if `mask` is greater than 128.
-    pub(super) fn mask(&self, mask: u8) -> [u8; ADDR_SIZE] {
+    fn mask(&self, mask: u8) -> [u8; ADDR_SIZE] {
         assert!(mask <= 128);
         let mut bytes = [0u8; ADDR_SIZE];
         let idx = (mask as usize) / 8;
         let modulus = (mask as usize) % 8;
-        let (first, second) = self.0.split_at(idx);
+        let octets = self.octets();
+        let (first, second) = octets.split_at(idx);
         bytes[0..idx].copy_from_slice(first);
         if idx < ADDR_SIZE {
             let part = second[0];
@@ -274,28 +168,23 @@ impl Address {
         bytes
     }
 
-    /// The solicited node for the given unicast address.
-    ///
-    /// # Panics
-    /// This function panics if the given address is not
-    /// unicast.
-    pub fn solicited_node(&self) -> Address {
-        assert!(self.is_unicast());
-        Address([
-            0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF,
-            self.0[13], self.0[14], self.0[15],
+    fn solicited_node(&self) -> Address {
+        assert!(self.x_is_unicast());
+        let o = self.octets();
+        Address::from([
+            0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, o[13],
+            o[14], o[15],
         ])
     }
 
-    /// Return the scope of the address.
-    pub(crate) fn multicast_scope(&self) -> MulticastScope {
+    fn x_multicast_scope(&self) -> MulticastScope {
         if self.is_multicast() {
-            return MulticastScope::from(self.as_bytes()[1] & 0b1111);
+            return MulticastScope::from(self.octets()[1] & 0b1111);
         }
 
         if self.is_link_local() {
             MulticastScope::LinkLocal
-        } else if self.is_unique_local() || self.is_global_unicast() {
+        } else if self.x_is_unique_local() || self.is_global_unicast() {
             // ULA are considered global scope
             // https://www.rfc-editor.org/rfc/rfc6724#section-3.1
             MulticastScope::Global
@@ -304,162 +193,34 @@ impl Address {
         }
     }
 
-    /// Convert to an `IpAddress`.
-    ///
-    /// Same as `.into()`, but works in `const`.
-    pub const fn into_address(self) -> super::IpAddress {
-        super::IpAddress::Ipv6(self)
-    }
-}
-
-impl From<::core::net::Ipv6Addr> for Address {
-    fn from(x: ::core::net::Ipv6Addr) -> Address {
-        Address(x.octets())
-    }
-}
-
-impl From<Address> for ::core::net::Ipv6Addr {
-    fn from(Address(x): Address) -> ::core::net::Ipv6Addr {
-        x.into()
-    }
-}
-
-impl fmt::Display for Address {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        if self.is_ipv4_mapped() {
-            return write!(
-                f,
-                "::ffff:{}.{}.{}.{}",
-                self.0[IPV4_MAPPED_PREFIX_SIZE + 0],
-                self.0[IPV4_MAPPED_PREFIX_SIZE + 1],
-                self.0[IPV4_MAPPED_PREFIX_SIZE + 2],
-                self.0[IPV4_MAPPED_PREFIX_SIZE + 3]
-            );
-        }
-
-        // The string representation of an IPv6 address should
-        // collapse a series of 16 bit sections that evaluate
-        // to 0 to "::"
-        //
-        // See https://tools.ietf.org/html/rfc4291#section-2.2
-        // for details.
-        enum State {
-            Head,
-            HeadBody,
-            Tail,
-            TailBody,
-        }
-        let mut words = [0u16; 8];
-        self.write_parts(&mut words);
-        let mut state = State::Head;
-        for word in words.iter() {
-            state = match (*word, &state) {
-                // Once a u16 equal to zero write a double colon and
-                // skip to the next non-zero u16.
-                (0, &State::Head) | (0, &State::HeadBody) => {
-                    write!(f, "::")?;
-                    State::Tail
-                }
-                // Continue iterating without writing any characters until
-                // we hit a non-zero value.
-                (0, &State::Tail) => State::Tail,
-                // When the state is Head or Tail write a u16 in hexadecimal
-                // without the leading colon if the value is not 0.
-                (_, &State::Head) => {
-                    write!(f, "{word:x}")?;
-                    State::HeadBody
-                }
-                (_, &State::Tail) => {
-                    write!(f, "{word:x}")?;
-                    State::TailBody
-                }
-                // Write the u16 with a leading colon when parsing a value
-                // that isn't the first in a section
-                (_, &State::HeadBody) | (_, &State::TailBody) => {
-                    write!(f, ":{word:x}")?;
-                    state
-                }
-            }
-        }
-        Ok(())
-    }
-}
-
-#[cfg(feature = "defmt")]
-impl defmt::Format for Address {
-    fn format(&self, f: defmt::Formatter) {
-        if self.is_ipv4_mapped() {
-            return defmt::write!(
-                f,
-                "::ffff:{}.{}.{}.{}",
-                self.0[IPV4_MAPPED_PREFIX_SIZE + 0],
-                self.0[IPV4_MAPPED_PREFIX_SIZE + 1],
-                self.0[IPV4_MAPPED_PREFIX_SIZE + 2],
-                self.0[IPV4_MAPPED_PREFIX_SIZE + 3]
-            );
-        }
-
-        // The string representation of an IPv6 address should
-        // collapse a series of 16 bit sections that evaluate
-        // to 0 to "::"
-        //
-        // See https://tools.ietf.org/html/rfc4291#section-2.2
-        // for details.
-        enum State {
-            Head,
-            HeadBody,
-            Tail,
-            TailBody,
-        }
-        let mut words = [0u16; 8];
-        self.write_parts(&mut words);
-        let mut state = State::Head;
-        for word in words.iter() {
-            state = match (*word, &state) {
-                // Once a u16 equal to zero write a double colon and
-                // skip to the next non-zero u16.
-                (0, &State::Head) | (0, &State::HeadBody) => {
-                    defmt::write!(f, "::");
-                    State::Tail
-                }
-                // Continue iterating without writing any characters until
-                // we hit a non-zero value.
-                (0, &State::Tail) => State::Tail,
-                // When the state is Head or Tail write a u16 in hexadecimal
-                // without the leading colon if the value is not 0.
-                (_, &State::Head) => {
-                    defmt::write!(f, "{:x}", word);
-                    State::HeadBody
-                }
-                (_, &State::Tail) => {
-                    defmt::write!(f, "{:x}", word);
-                    State::TailBody
-                }
-                // Write the u16 with a leading colon when parsing a value
-                // that isn't the first in a section
-                (_, &State::HeadBody) | (_, &State::TailBody) => {
-                    defmt::write!(f, ":{:x}", word);
-                    state
+    fn prefix_len(&self) -> Option<u8> {
+        let mut ones = true;
+        let mut prefix_len = 0;
+        for byte in self.octets() {
+            let mut mask = 0x80;
+            for _ in 0..8 {
+                let one = byte & mask != 0;
+                if ones {
+                    // Expect 1s until first 0
+                    if one {
+                        prefix_len += 1;
+                    } else {
+                        ones = false;
+                    }
+                } else if one {
+                    // 1 where 0 was expected
+                    return None;
                 }
+                mask >>= 1;
             }
         }
-    }
-}
-
-#[cfg(feature = "proto-ipv4")]
-/// Convert the given IPv4 address into a IPv4-mapped IPv6 address
-impl From<ipv4::Address> for Address {
-    fn from(address: ipv4::Address) -> Self {
-        let mut b = [0_u8; ADDR_SIZE];
-        b[..Self::IPV4_MAPPED_PREFIX.len()].copy_from_slice(&Self::IPV4_MAPPED_PREFIX);
-        b[Self::IPV4_MAPPED_PREFIX.len()..].copy_from_slice(&address.0);
-        Self(b)
+        Some(prefix_len)
     }
 }
 
 /// A specification of an IPv6 CIDR block, containing an address and a variable-length
 /// subnet masking prefix length.
-#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default)]
+#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
 pub struct Cidr {
     address: Address,
     prefix_len: u8,
@@ -470,10 +231,7 @@ impl Cidr {
     ///
     /// [solicited node prefix]: https://tools.ietf.org/html/rfc4291#section-2.7.1
     pub const SOLICITED_NODE_PREFIX: Cidr = Cidr {
-        address: Address([
-            0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0x00,
-            0x00, 0x00,
-        ]),
+        address: Address::new(0xff02, 0, 0, 0, 0, 1, 0xff00, 0),
         prefix_len: 104,
     };
 
@@ -763,14 +521,14 @@ impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
     #[inline]
     pub fn set_src_addr(&mut self, value: Address) {
         let data = self.buffer.as_mut();
-        data[field::SRC_ADDR].copy_from_slice(value.as_bytes());
+        data[field::SRC_ADDR].copy_from_slice(&value.octets());
     }
 
     /// Set the destination address field.
     #[inline]
     pub fn set_dst_addr(&mut self, value: Address) {
         let data = self.buffer.as_mut();
-        data[field::DST_ADDR].copy_from_slice(value.as_bytes());
+        data[field::DST_ADDR].copy_from_slice(&value.octets());
     }
 
     /// Return a mutable pointer to the payload.
@@ -904,26 +662,17 @@ impl<T: AsRef<[u8]>> PrettyPrint for Packet<T> {
 
 #[cfg(test)]
 pub(crate) mod test {
-    use super::Error;
-    use super::{Address, Cidr};
-    use super::{Packet, Protocol, Repr};
+    use super::*;
     use crate::wire::pretty_print::PrettyPrinter;
 
-    #[cfg(feature = "proto-ipv4")]
-    use crate::wire::ipv4::Address as Ipv4Address;
-
     #[allow(unused)]
-    pub(crate) const MOCK_IP_ADDR_1: Address =
-        Address([0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]);
+    pub(crate) const MOCK_IP_ADDR_1: Address = Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 1);
     #[allow(unused)]
-    pub(crate) const MOCK_IP_ADDR_2: Address =
-        Address([0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2]);
+    pub(crate) const MOCK_IP_ADDR_2: Address = Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 2);
     #[allow(unused)]
-    pub(crate) const MOCK_IP_ADDR_3: Address =
-        Address([0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3]);
+    pub(crate) const MOCK_IP_ADDR_3: Address = Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 3);
     #[allow(unused)]
-    pub(crate) const MOCK_IP_ADDR_4: Address =
-        Address([0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4]);
+    pub(crate) const MOCK_IP_ADDR_4: Address = Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 4);
     #[allow(unused)]
     pub(crate) const MOCK_UNSPECIFIED: Address = Address::UNSPECIFIED;
 
@@ -933,18 +682,18 @@ pub(crate) mod test {
 
     #[test]
     fn test_basic_multicast() {
-        assert!(!Address::LINK_LOCAL_ALL_ROUTERS.is_unspecified());
-        assert!(Address::LINK_LOCAL_ALL_ROUTERS.is_multicast());
-        assert!(!Address::LINK_LOCAL_ALL_ROUTERS.is_link_local());
-        assert!(!Address::LINK_LOCAL_ALL_ROUTERS.is_loopback());
-        assert!(!Address::LINK_LOCAL_ALL_ROUTERS.is_unique_local());
-        assert!(!Address::LINK_LOCAL_ALL_ROUTERS.is_global_unicast());
-        assert!(!Address::LINK_LOCAL_ALL_NODES.is_unspecified());
-        assert!(Address::LINK_LOCAL_ALL_NODES.is_multicast());
-        assert!(!Address::LINK_LOCAL_ALL_NODES.is_link_local());
-        assert!(!Address::LINK_LOCAL_ALL_NODES.is_loopback());
-        assert!(!Address::LINK_LOCAL_ALL_NODES.is_unique_local());
-        assert!(!Address::LINK_LOCAL_ALL_NODES.is_global_unicast());
+        assert!(!LINK_LOCAL_ALL_ROUTERS.is_unspecified());
+        assert!(LINK_LOCAL_ALL_ROUTERS.is_multicast());
+        assert!(!LINK_LOCAL_ALL_ROUTERS.is_link_local());
+        assert!(!LINK_LOCAL_ALL_ROUTERS.is_loopback());
+        assert!(!LINK_LOCAL_ALL_ROUTERS.x_is_unique_local());
+        assert!(!LINK_LOCAL_ALL_ROUTERS.is_global_unicast());
+        assert!(!LINK_LOCAL_ALL_NODES.is_unspecified());
+        assert!(LINK_LOCAL_ALL_NODES.is_multicast());
+        assert!(!LINK_LOCAL_ALL_NODES.is_link_local());
+        assert!(!LINK_LOCAL_ALL_NODES.is_loopback());
+        assert!(!LINK_LOCAL_ALL_NODES.x_is_unique_local());
+        assert!(!LINK_LOCAL_ALL_NODES.is_global_unicast());
     }
 
     #[test]
@@ -953,18 +702,18 @@ pub(crate) mod test {
         assert!(!LINK_LOCAL_ADDR.is_multicast());
         assert!(LINK_LOCAL_ADDR.is_link_local());
         assert!(!LINK_LOCAL_ADDR.is_loopback());
-        assert!(!LINK_LOCAL_ADDR.is_unique_local());
+        assert!(!LINK_LOCAL_ADDR.x_is_unique_local());
         assert!(!LINK_LOCAL_ADDR.is_global_unicast());
     }
 
     #[test]
     fn test_basic_loopback() {
-        assert!(!Address::LOOPBACK.is_unspecified());
-        assert!(!Address::LOOPBACK.is_multicast());
-        assert!(!Address::LOOPBACK.is_link_local());
-        assert!(Address::LOOPBACK.is_loopback());
-        assert!(!Address::LOOPBACK.is_unique_local());
-        assert!(!Address::LOOPBACK.is_global_unicast());
+        assert!(!Address::LOCALHOST.is_unspecified());
+        assert!(!Address::LOCALHOST.is_multicast());
+        assert!(!Address::LOCALHOST.is_link_local());
+        assert!(Address::LOCALHOST.is_loopback());
+        assert!(!Address::LOCALHOST.x_is_unique_local());
+        assert!(!Address::LOCALHOST.is_global_unicast());
     }
 
     #[test]
@@ -973,7 +722,7 @@ pub(crate) mod test {
         assert!(!UNIQUE_LOCAL_ADDR.is_multicast());
         assert!(!UNIQUE_LOCAL_ADDR.is_link_local());
         assert!(!UNIQUE_LOCAL_ADDR.is_loopback());
-        assert!(UNIQUE_LOCAL_ADDR.is_unique_local());
+        assert!(UNIQUE_LOCAL_ADDR.x_is_unique_local());
         assert!(!UNIQUE_LOCAL_ADDR.is_global_unicast());
     }
 
@@ -983,87 +732,10 @@ pub(crate) mod test {
         assert!(!GLOBAL_UNICAST_ADDR.is_multicast());
         assert!(!GLOBAL_UNICAST_ADDR.is_link_local());
         assert!(!GLOBAL_UNICAST_ADDR.is_loopback());
-        assert!(!GLOBAL_UNICAST_ADDR.is_unique_local());
+        assert!(!GLOBAL_UNICAST_ADDR.x_is_unique_local());
         assert!(GLOBAL_UNICAST_ADDR.is_global_unicast());
     }
 
-    #[test]
-    fn test_address_format() {
-        assert_eq!("ff02::1", format!("{}", Address::LINK_LOCAL_ALL_NODES));
-        assert_eq!("fe80::1", format!("{LINK_LOCAL_ADDR}"));
-        assert_eq!(
-            "fe80::7f00:0:1",
-            format!(
-                "{}",
-                Address::new(0xfe80, 0, 0, 0, 0, 0x7f00, 0x0000, 0x0001)
-            )
-        );
-        assert_eq!("::", format!("{}", Address::UNSPECIFIED));
-        assert_eq!("::1", format!("{}", Address::LOOPBACK));
-
-        #[cfg(feature = "proto-ipv4")]
-        assert_eq!(
-            "::ffff:192.168.1.1",
-            format!("{}", Address::from(Ipv4Address::new(192, 168, 1, 1)))
-        );
-    }
-
-    #[test]
-    fn test_new() {
-        assert_eq!(
-            Address::new(0xff02, 0, 0, 0, 0, 0, 0, 1),
-            Address::LINK_LOCAL_ALL_NODES
-        );
-        assert_eq!(
-            Address::new(0xff02, 0, 0, 0, 0, 0, 0, 2),
-            Address::LINK_LOCAL_ALL_ROUTERS
-        );
-        assert_eq!(Address::new(0, 0, 0, 0, 0, 0, 0, 1), Address::LOOPBACK);
-        assert_eq!(Address::new(0, 0, 0, 0, 0, 0, 0, 0), Address::UNSPECIFIED);
-        assert_eq!(Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 1), LINK_LOCAL_ADDR);
-    }
-
-    #[test]
-    fn test_from_parts() {
-        assert_eq!(
-            Address::from_parts(&[0xff02, 0, 0, 0, 0, 0, 0, 1]),
-            Address::LINK_LOCAL_ALL_NODES
-        );
-        assert_eq!(
-            Address::from_parts(&[0xff02, 0, 0, 0, 0, 0, 0, 2]),
-            Address::LINK_LOCAL_ALL_ROUTERS
-        );
-        assert_eq!(
-            Address::from_parts(&[0, 0, 0, 0, 0, 0, 0, 1]),
-            Address::LOOPBACK
-        );
-        assert_eq!(
-            Address::from_parts(&[0, 0, 0, 0, 0, 0, 0, 0]),
-            Address::UNSPECIFIED
-        );
-        assert_eq!(
-            Address::from_parts(&[0xfe80, 0, 0, 0, 0, 0, 0, 1]),
-            LINK_LOCAL_ADDR
-        );
-    }
-
-    #[test]
-    fn test_write_parts() {
-        let mut bytes = [0u16; 8];
-        {
-            Address::LOOPBACK.write_parts(&mut bytes);
-            assert_eq!(Address::LOOPBACK, Address::from_parts(&bytes));
-        }
-        {
-            Address::LINK_LOCAL_ALL_ROUTERS.write_parts(&mut bytes);
-            assert_eq!(Address::LINK_LOCAL_ALL_ROUTERS, Address::from_parts(&bytes));
-        }
-        {
-            LINK_LOCAL_ADDR.write_parts(&mut bytes);
-            assert_eq!(LINK_LOCAL_ADDR, Address::from_parts(&bytes));
-        }
-    }
-
     #[test]
     fn test_mask() {
         let addr = Address::new(0x0123, 0x4567, 0x89ab, 0, 0, 0, 0, 1);
@@ -1089,35 +761,6 @@ pub(crate) mod test {
         );
     }
 
-    #[cfg(feature = "proto-ipv4")]
-    #[test]
-    fn test_is_ipv4_mapped() {
-        assert!(!Address::UNSPECIFIED.is_ipv4_mapped());
-        assert!(Address::from(Ipv4Address::new(192, 168, 1, 1)).is_ipv4_mapped());
-    }
-
-    #[cfg(feature = "proto-ipv4")]
-    #[test]
-    fn test_as_ipv4() {
-        assert_eq!(None, Address::UNSPECIFIED.as_ipv4());
-
-        let ipv4 = Ipv4Address::new(192, 168, 1, 1);
-        assert_eq!(Some(ipv4), Address::from(ipv4).as_ipv4());
-    }
-
-    #[cfg(feature = "proto-ipv4")]
-    #[test]
-    fn test_from_ipv4_address() {
-        assert_eq!(
-            Address([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 192, 168, 1, 1]),
-            Address::from(Ipv4Address::new(192, 168, 1, 1))
-        );
-        assert_eq!(
-            Address([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 222, 1, 41, 90]),
-            Address::from(Ipv4Address::new(222, 1, 41, 90))
-        );
-    }
-
     #[test]
     fn test_cidr() {
         // fe80::1/56
@@ -1241,16 +884,19 @@ pub(crate) mod test {
             assert!(!cidr.contains_addr(&addr));
         }
 
-        for subnet in subnets.iter().map(|&(a, p)| Cidr::new(Address(a), p)) {
+        for subnet in subnets.iter().map(|&(a, p)| Cidr::new(Address::from(a), p)) {
             assert!(cidr.contains_subnet(&subnet));
         }
 
-        for subnet in not_subnets.iter().map(|&(a, p)| Cidr::new(Address(a), p)) {
+        for subnet in not_subnets
+            .iter()
+            .map(|&(a, p)| Cidr::new(Address::from(a), p))
+        {
             assert!(!cidr.contains_subnet(&subnet));
         }
 
         let cidr_without_prefix = Cidr::new(LINK_LOCAL_ADDR, 0);
-        assert!(cidr_without_prefix.contains_addr(&Address::LOOPBACK));
+        assert!(cidr_without_prefix.contains_addr(&Address::LOCALHOST));
     }
 
     #[test]
@@ -1259,56 +905,56 @@ pub(crate) mod test {
         let _ = Address::from_bytes(&[0u8; 15]);
     }
 
-    #[test]
-    #[should_panic(expected = "data.len() >= 8")]
-    fn test_from_parts_too_long() {
-        let _ = Address::from_parts(&[0u16; 7]);
-    }
-
     #[test]
     fn test_scope() {
         use super::*;
         assert_eq!(
-            Address::new(0xff01, 0, 0, 0, 0, 0, 0, 1).multicast_scope(),
+            Address::new(0xff01, 0, 0, 0, 0, 0, 0, 1).x_multicast_scope(),
             MulticastScope::InterfaceLocal
         );
         assert_eq!(
-            Address::new(0xff02, 0, 0, 0, 0, 0, 0, 1).multicast_scope(),
+            Address::new(0xff02, 0, 0, 0, 0, 0, 0, 1).x_multicast_scope(),
             MulticastScope::LinkLocal
         );
         assert_eq!(
-            Address::new(0xff03, 0, 0, 0, 0, 0, 0, 1).multicast_scope(),
+            Address::new(0xff03, 0, 0, 0, 0, 0, 0, 1).x_multicast_scope(),
             MulticastScope::Unknown
         );
         assert_eq!(
-            Address::new(0xff04, 0, 0, 0, 0, 0, 0, 1).multicast_scope(),
+            Address::new(0xff04, 0, 0, 0, 0, 0, 0, 1).x_multicast_scope(),
             MulticastScope::AdminLocal
         );
         assert_eq!(
-            Address::new(0xff05, 0, 0, 0, 0, 0, 0, 1).multicast_scope(),
+            Address::new(0xff05, 0, 0, 0, 0, 0, 0, 1).x_multicast_scope(),
             MulticastScope::SiteLocal
         );
         assert_eq!(
-            Address::new(0xff08, 0, 0, 0, 0, 0, 0, 1).multicast_scope(),
+            Address::new(0xff08, 0, 0, 0, 0, 0, 0, 1).x_multicast_scope(),
             MulticastScope::OrganizationLocal
         );
         assert_eq!(
-            Address::new(0xff0e, 0, 0, 0, 0, 0, 0, 1).multicast_scope(),
+            Address::new(0xff0e, 0, 0, 0, 0, 0, 0, 1).x_multicast_scope(),
             MulticastScope::Global
         );
 
         assert_eq!(
-            Address::LINK_LOCAL_ALL_NODES.multicast_scope(),
+            LINK_LOCAL_ALL_NODES.x_multicast_scope(),
             MulticastScope::LinkLocal
         );
 
         // For source address selection, unicast addresses also have a scope:
-        assert_eq!(LINK_LOCAL_ADDR.multicast_scope(), MulticastScope::LinkLocal);
         assert_eq!(
-            GLOBAL_UNICAST_ADDR.multicast_scope(),
+            LINK_LOCAL_ADDR.x_multicast_scope(),
+            MulticastScope::LinkLocal
+        );
+        assert_eq!(
+            GLOBAL_UNICAST_ADDR.x_multicast_scope(),
+            MulticastScope::Global
+        );
+        assert_eq!(
+            UNIQUE_LOCAL_ADDR.x_multicast_scope(),
             MulticastScope::Global
         );
-        assert_eq!(UNIQUE_LOCAL_ADDR.multicast_scope(), MulticastScope::Global);
     }
 
     static REPR_PACKET_BYTES: [u8; 52] = [
@@ -1323,11 +969,8 @@ pub(crate) mod test {
 
     const fn packet_repr() -> Repr {
         Repr {
-            src_addr: Address([
-                0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                0x00, 0x01,
-            ]),
-            dst_addr: Address::LINK_LOCAL_ALL_NODES,
+            src_addr: Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 1),
+            dst_addr: LINK_LOCAL_ALL_NODES,
             next_header: Protocol::Udp,
             payload_len: 12,
             hop_limit: 64,
@@ -1345,14 +988,8 @@ pub(crate) mod test {
         assert_eq!(packet.payload_len() as usize, REPR_PAYLOAD_BYTES.len());
         assert_eq!(packet.next_header(), Protocol::Udp);
         assert_eq!(packet.hop_limit(), 0x40);
-        assert_eq!(
-            packet.src_addr(),
-            Address([
-                0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                0x00, 0x01
-            ])
-        );
-        assert_eq!(packet.dst_addr(), Address::LINK_LOCAL_ALL_NODES);
+        assert_eq!(packet.src_addr(), Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 1));
+        assert_eq!(packet.dst_addr(), LINK_LOCAL_ALL_NODES);
         assert_eq!(packet.payload(), &REPR_PAYLOAD_BYTES[..]);
     }
 
@@ -1374,8 +1011,8 @@ pub(crate) mod test {
         packet.set_payload_len(0xc);
         packet.set_next_header(Protocol::Udp);
         packet.set_hop_limit(0xfe);
-        packet.set_src_addr(Address::LINK_LOCAL_ALL_ROUTERS);
-        packet.set_dst_addr(Address::LINK_LOCAL_ALL_NODES);
+        packet.set_src_addr(LINK_LOCAL_ALL_ROUTERS);
+        packet.set_dst_addr(LINK_LOCAL_ALL_NODES);
         packet
             .payload_mut()
             .copy_from_slice(&REPR_PAYLOAD_BYTES[..]);

+ 5 - 5
src/wire/ipv6routing.rs

@@ -1,7 +1,7 @@
 use super::{Error, Result};
 use core::fmt;
 
-use crate::wire::Ipv6Address as Address;
+use crate::wire::{Ipv6Address as Address, Ipv6AddressExt};
 
 enum_with_unknown! {
     /// IPv6 Extension Routing Header Routing Type
@@ -286,7 +286,7 @@ impl<T: AsRef<[u8]> + AsMut<[u8]>> Header<T> {
     /// This function may panic if this header is not the Type 2 Routing Header routing type.
     pub fn set_home_address(&mut self, value: Address) {
         let data = self.buffer.as_mut();
-        data[field::HOME_ADDRESS].copy_from_slice(value.as_bytes());
+        data[field::HOME_ADDRESS].copy_from_slice(&value.octets());
     }
 }
 
@@ -399,7 +399,7 @@ impl<'a> Repr<'a> {
     pub const fn buffer_len(&self) -> usize {
         match self {
             // Routing Type + Segments Left + Reserved + Home Address
-            Repr::Type2 { home_address, .. } => 2 + 4 + home_address.as_bytes().len(),
+            Repr::Type2 { home_address, .. } => 2 + 4 + home_address.octets().len(),
             Repr::Rpl { addresses, .. } => 2 + 4 + addresses.len(),
         }
     }
@@ -484,7 +484,7 @@ mod test {
     // A representation of a Type 2 Routing header
     static REPR_TYPE2: Repr = Repr::Type2 {
         segments_left: 1,
-        home_address: Address::LOOPBACK,
+        home_address: Address::LOCALHOST,
     };
 
     // A Source Routing Header with full IPv6 addresses in bytes
@@ -552,7 +552,7 @@ mod test {
         let header = Header::new_unchecked(&BYTES_TYPE2[..]);
         assert_eq!(header.routing_type(), Type::Type2);
         assert_eq!(header.segments_left(), 1);
-        assert_eq!(header.home_address(), Address::LOOPBACK);
+        assert_eq!(header.home_address(), Address::LOCALHOST);
 
         let header = Header::new_unchecked(&BYTES_SRH_FULL[..]);
         assert_eq!(header.routing_type(), Type::Rpl);

+ 23 - 29
src/wire/mld.rs

@@ -8,7 +8,7 @@ use byteorder::{ByteOrder, NetworkEndian};
 
 use super::{Error, Result};
 use crate::wire::icmpv6::{field, Message, Packet};
-use crate::wire::Ipv6Address;
+use crate::wire::{Ipv6Address, Ipv6AddressExt};
 
 enum_with_unknown! {
     /// MLDv2 Multicast Listener Report Record Type. See [RFC 3810 § 5.2.12] for
@@ -110,7 +110,7 @@ impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
     #[inline]
     pub fn set_mcast_addr(&mut self, addr: Ipv6Address) {
         let data = self.buffer.as_mut();
-        data[field::QUERY_MCAST_ADDR].copy_from_slice(addr.as_bytes());
+        data[field::QUERY_MCAST_ADDR].copy_from_slice(&addr.octets());
     }
 
     /// Set the Suppress Router-Side Processing flag.
@@ -281,7 +281,7 @@ impl<T: AsMut<[u8]> + AsRef<[u8]>> AddressRecord<T> {
     pub fn set_mcast_addr(&mut self, addr: Ipv6Address) {
         assert!(addr.is_multicast());
         let data = self.buffer.as_mut();
-        data[field::RECORD_MCAST_ADDR].copy_from_slice(addr.as_bytes());
+        data[field::RECORD_MCAST_ADDR].copy_from_slice(&addr.octets());
     }
 }
 
@@ -460,7 +460,7 @@ mod test {
     use super::*;
     use crate::phy::ChecksumCapabilities;
     use crate::wire::icmpv6::Message;
-    use crate::wire::Icmpv6Repr;
+    use crate::wire::{Icmpv6Repr, IPV6_LINK_LOCAL_ALL_NODES, IPV6_LINK_LOCAL_ALL_ROUTERS};
 
     static QUERY_PACKET_BYTES: [u8; 44] = [
         0x82, 0x00, 0x73, 0x74, 0x04, 0x00, 0x00, 0x00, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -489,7 +489,7 @@ mod test {
         match ty {
             Message::MldQuery => Icmpv6Repr::Mld(Repr::Query {
                 max_resp_code: 0x400,
-                mcast_addr: Ipv6Address::LINK_LOCAL_ALL_NODES,
+                mcast_addr: IPV6_LINK_LOCAL_ALL_NODES,
                 s_flag: true,
                 qrv: 0x02,
                 qqic: 0x12,
@@ -513,14 +513,14 @@ mod test {
         assert_eq!(packet.msg_code(), 0);
         assert_eq!(packet.checksum(), 0x7374);
         assert_eq!(packet.max_resp_code(), 0x0400);
-        assert_eq!(packet.mcast_addr(), Ipv6Address::LINK_LOCAL_ALL_NODES);
+        assert_eq!(packet.mcast_addr(), IPV6_LINK_LOCAL_ALL_NODES);
         assert!(packet.s_flag());
         assert_eq!(packet.qrv(), 0x02);
         assert_eq!(packet.qqic(), 0x12);
         assert_eq!(packet.num_srcs(), 0x01);
         assert_eq!(
             Ipv6Address::from_bytes(packet.payload()),
-            Ipv6Address::LINK_LOCAL_ALL_ROUTERS
+            IPV6_LINK_LOCAL_ALL_ROUTERS
         );
     }
 
@@ -531,19 +531,16 @@ mod test {
         packet.set_msg_type(Message::MldQuery);
         packet.set_msg_code(0);
         packet.set_max_resp_code(0x0400);
-        packet.set_mcast_addr(Ipv6Address::LINK_LOCAL_ALL_NODES);
+        packet.set_mcast_addr(IPV6_LINK_LOCAL_ALL_NODES);
         packet.set_s_flag();
         packet.set_qrv(0x02);
         packet.set_qqic(0x12);
         packet.set_num_srcs(0x01);
         packet
             .payload_mut()
-            .copy_from_slice(Ipv6Address::LINK_LOCAL_ALL_ROUTERS.as_bytes());
+            .copy_from_slice(&IPV6_LINK_LOCAL_ALL_ROUTERS.octets());
         packet.clear_reserved();
-        packet.fill_checksum(
-            &Ipv6Address::LINK_LOCAL_ALL_NODES,
-            &Ipv6Address::LINK_LOCAL_ALL_ROUTERS,
-        );
+        packet.fill_checksum(&IPV6_LINK_LOCAL_ALL_NODES, &IPV6_LINK_LOCAL_ALL_ROUTERS);
         assert_eq!(&*packet.into_inner(), &QUERY_PACKET_BYTES[..]);
     }
 
@@ -558,10 +555,10 @@ mod test {
         assert_eq!(addr_rcrd.record_type(), RecordType::ModeIsInclude);
         assert_eq!(addr_rcrd.aux_data_len(), 0x00);
         assert_eq!(addr_rcrd.num_srcs(), 0x01);
-        assert_eq!(addr_rcrd.mcast_addr(), Ipv6Address::LINK_LOCAL_ALL_NODES);
+        assert_eq!(addr_rcrd.mcast_addr(), IPV6_LINK_LOCAL_ALL_NODES);
         assert_eq!(
             Ipv6Address::from_bytes(addr_rcrd.payload()),
-            Ipv6Address::LINK_LOCAL_ALL_ROUTERS
+            IPV6_LINK_LOCAL_ALL_ROUTERS
         );
     }
 
@@ -578,15 +575,12 @@ mod test {
             addr_rcrd.set_record_type(RecordType::ModeIsInclude);
             addr_rcrd.set_aux_data_len(0);
             addr_rcrd.set_num_srcs(1);
-            addr_rcrd.set_mcast_addr(Ipv6Address::LINK_LOCAL_ALL_NODES);
+            addr_rcrd.set_mcast_addr(IPV6_LINK_LOCAL_ALL_NODES);
             addr_rcrd
                 .payload_mut()
-                .copy_from_slice(Ipv6Address::LINK_LOCAL_ALL_ROUTERS.as_bytes());
+                .copy_from_slice(&IPV6_LINK_LOCAL_ALL_ROUTERS.octets());
         }
-        packet.fill_checksum(
-            &Ipv6Address::LINK_LOCAL_ALL_NODES,
-            &Ipv6Address::LINK_LOCAL_ALL_ROUTERS,
-        );
+        packet.fill_checksum(&IPV6_LINK_LOCAL_ALL_NODES, &IPV6_LINK_LOCAL_ALL_ROUTERS);
         assert_eq!(&*packet.into_inner(), &REPORT_PACKET_BYTES[..]);
     }
 
@@ -594,8 +588,8 @@ mod test {
     fn test_query_repr_parse() {
         let packet = Packet::new_unchecked(&QUERY_PACKET_BYTES[..]);
         let repr = Icmpv6Repr::parse(
-            &Ipv6Address::LINK_LOCAL_ALL_NODES,
-            &Ipv6Address::LINK_LOCAL_ALL_ROUTERS,
+            &IPV6_LINK_LOCAL_ALL_NODES,
+            &IPV6_LINK_LOCAL_ALL_ROUTERS,
             &packet,
             &ChecksumCapabilities::default(),
         );
@@ -606,8 +600,8 @@ mod test {
     fn test_report_repr_parse() {
         let packet = Packet::new_unchecked(&REPORT_PACKET_BYTES[..]);
         let repr = Icmpv6Repr::parse(
-            &Ipv6Address::LINK_LOCAL_ALL_NODES,
-            &Ipv6Address::LINK_LOCAL_ALL_ROUTERS,
+            &IPV6_LINK_LOCAL_ALL_NODES,
+            &IPV6_LINK_LOCAL_ALL_ROUTERS,
             &packet,
             &ChecksumCapabilities::default(),
         );
@@ -620,8 +614,8 @@ mod test {
         let mut packet = Packet::new_unchecked(&mut bytes[..]);
         let repr = create_repr(Message::MldQuery);
         repr.emit(
-            &Ipv6Address::LINK_LOCAL_ALL_NODES,
-            &Ipv6Address::LINK_LOCAL_ALL_ROUTERS,
+            &IPV6_LINK_LOCAL_ALL_NODES,
+            &IPV6_LINK_LOCAL_ALL_ROUTERS,
             &mut packet,
             &ChecksumCapabilities::default(),
         );
@@ -634,8 +628,8 @@ mod test {
         let mut packet = Packet::new_unchecked(&mut bytes[..]);
         let repr = create_repr(Message::MldReport);
         repr.emit(
-            &Ipv6Address::LINK_LOCAL_ALL_NODES,
-            &Ipv6Address::LINK_LOCAL_ALL_ROUTERS,
+            &IPV6_LINK_LOCAL_ALL_NODES,
+            &IPV6_LINK_LOCAL_ALL_ROUTERS,
             &mut packet,
             &ChecksumCapabilities::default(),
         );

+ 12 - 3
src/wire/mod.rs

@@ -188,15 +188,24 @@ pub use self::ip::{
 pub use self::ipv4::{
     Address as Ipv4Address, Cidr as Ipv4Cidr, Key as Ipv4FragKey, Packet as Ipv4Packet,
     Repr as Ipv4Repr, HEADER_LEN as IPV4_HEADER_LEN, MIN_MTU as IPV4_MIN_MTU,
+    MULTICAST_ALL_ROUTERS as IPV4_MULTICAST_ALL_ROUTERS,
+    MULTICAST_ALL_SYSTEMS as IPV4_MULTICAST_ALL_SYSTEMS,
 };
 
-#[cfg(feature = "proto-ipv6")]
-pub(crate) use self::ipv6::MulticastScope as Ipv6MulticastScope;
+#[cfg(feature = "proto-ipv4")]
+pub(crate) use self::ipv4::AddressExt as Ipv4AddressExt;
+
 #[cfg(feature = "proto-ipv6")]
 pub use self::ipv6::{
     Address as Ipv6Address, Cidr as Ipv6Cidr, Packet as Ipv6Packet, Repr as Ipv6Repr,
-    HEADER_LEN as IPV6_HEADER_LEN, MIN_MTU as IPV6_MIN_MTU,
+    HEADER_LEN as IPV6_HEADER_LEN,
+    LINK_LOCAL_ALL_MLDV2_ROUTERS as IPV6_LINK_LOCAL_ALL_MLDV2_ROUTERS,
+    LINK_LOCAL_ALL_NODES as IPV6_LINK_LOCAL_ALL_NODES,
+    LINK_LOCAL_ALL_ROUTERS as IPV6_LINK_LOCAL_ALL_ROUTERS,
+    LINK_LOCAL_ALL_RPL_NODES as IPV6_LINK_LOCAL_ALL_RPL_NODES, MIN_MTU as IPV6_MIN_MTU,
 };
+#[cfg(feature = "proto-ipv6")]
+pub(crate) use self::ipv6::{AddressExt as Ipv6AddressExt, MulticastScope as Ipv6MulticastScope};
 
 #[cfg(feature = "proto-ipv6")]
 pub use self::ipv6option::{

+ 5 - 7
src/wire/ndisc.rs

@@ -4,8 +4,8 @@ use byteorder::{ByteOrder, NetworkEndian};
 use super::{Error, Result};
 use crate::time::Duration;
 use crate::wire::icmpv6::{field, Message, Packet};
-use crate::wire::Ipv6Address;
 use crate::wire::RawHardwareAddress;
+use crate::wire::{Ipv6Address, Ipv6AddressExt};
 use crate::wire::{NdiscOption, NdiscOptionRepr};
 use crate::wire::{NdiscPrefixInformation, NdiscRedirectedHeader};
 
@@ -159,7 +159,7 @@ impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
     #[inline]
     pub fn set_target_addr(&mut self, value: Ipv6Address) {
         let data = self.buffer.as_mut();
-        data[field::TARGET_ADDR].copy_from_slice(value.as_bytes());
+        data[field::TARGET_ADDR].copy_from_slice(&value.octets());
     }
 }
 
@@ -184,7 +184,7 @@ impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
     #[inline]
     pub fn set_dest_addr(&mut self, value: Ipv6Address) {
         let data = self.buffer.as_mut();
-        data[field::DEST_ADDR].copy_from_slice(value.as_bytes());
+        data[field::DEST_ADDR].copy_from_slice(&value.octets());
     }
 }
 
@@ -462,10 +462,8 @@ mod test {
     use crate::wire::EthernetAddress;
     use crate::wire::Icmpv6Repr;
 
-    const MOCK_IP_ADDR_1: Ipv6Address =
-        Ipv6Address([0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]);
-    const MOCK_IP_ADDR_2: Ipv6Address =
-        Ipv6Address([0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2]);
+    const MOCK_IP_ADDR_1: Ipv6Address = Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 1);
+    const MOCK_IP_ADDR_2: Ipv6Address = Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 2);
 
     static ROUTER_ADVERT_BYTES: [u8; 24] = [
         0x86, 0x00, 0xa9, 0xde, 0x40, 0x80, 0x03, 0x84, 0x00, 0x00, 0x03, 0x84, 0x00, 0x00, 0x03,

+ 2 - 2
src/wire/ndiscoption.rs

@@ -4,7 +4,7 @@ use core::fmt;
 
 use super::{Error, Result};
 use crate::time::Duration;
-use crate::wire::{Ipv6Address, Ipv6Packet, Ipv6Repr, MAX_HARDWARE_ADDRESS_LEN};
+use crate::wire::{Ipv6Address, Ipv6AddressExt, Ipv6Packet, Ipv6Repr, MAX_HARDWARE_ADDRESS_LEN};
 
 use crate::wire::RawHardwareAddress;
 
@@ -356,7 +356,7 @@ impl<T: AsRef<[u8]> + AsMut<[u8]>> NdiscOption<T> {
     #[inline]
     pub fn set_prefix(&mut self, addr: Ipv6Address) {
         let data = self.buffer.as_mut();
-        data[field::PREFIX].copy_from_slice(addr.as_bytes());
+        data[field::PREFIX].copy_from_slice(&addr.octets());
     }
 }
 

+ 9 - 11
src/wire/rpl.rs

@@ -6,7 +6,7 @@ use byteorder::{ByteOrder, NetworkEndian};
 
 use super::{Error, Result};
 use crate::wire::icmpv6::Packet;
-use crate::wire::ipv6::Address;
+use crate::wire::ipv6::{Address, AddressExt};
 
 #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
@@ -508,7 +508,7 @@ impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
     pub fn set_dao_dodag_id(&mut self, address: Option<Address>) {
         match address {
             Some(address) => {
-                self.buffer.as_mut()[field::DAO_DODAG_ID].copy_from_slice(address.as_bytes());
+                self.buffer.as_mut()[field::DAO_DODAG_ID].copy_from_slice(&address.octets());
                 self.set_dao_dodag_id_present(true);
             }
             None => {
@@ -594,7 +594,7 @@ impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
     pub fn set_dao_ack_dodag_id(&mut self, address: Option<Address>) {
         match address {
             Some(address) => {
-                self.buffer.as_mut()[field::DAO_ACK_DODAG_ID].copy_from_slice(address.as_bytes());
+                self.buffer.as_mut()[field::DAO_ACK_DODAG_ID].copy_from_slice(&address.octets());
                 self.set_dao_ack_dodag_id_present(true);
             }
             None => {
@@ -866,7 +866,7 @@ pub mod options {
     use byteorder::{ByteOrder, NetworkEndian};
 
     use super::{Error, InstanceId, Result};
-    use crate::wire::ipv6::Address;
+    use crate::wire::ipv6::{Address, AddressExt};
 
     /// A read/write wrapper around a RPL Control Message Option.
     #[derive(Debug, Clone)]
@@ -1497,7 +1497,7 @@ pub mod options {
         #[inline]
         pub fn set_transit_info_parent_address(&mut self, address: Address) {
             self.buffer.as_mut()[field::TRANSIT_INFO_PARENT_ADDRESS]
-                .copy_from_slice(address.as_bytes());
+                .copy_from_slice(&address.octets());
         }
     }
 
@@ -2095,7 +2095,7 @@ pub mod options {
                 Repr::DagMetricContainer => todo!(),
                 Repr::RouteInformation { prefix, .. } => 2 + 6 + prefix.len(),
                 Repr::DodagConfiguration { .. } => 2 + 14,
-                Repr::RplTarget { prefix, .. } => 2 + 2 + prefix.0.len(),
+                Repr::RplTarget { prefix, .. } => 2 + 2 + prefix.octets().len(),
                 Repr::TransitInformation { parent_address, .. } => {
                     2 + 4 + if parent_address.is_some() { 16 } else { 0 }
                 }
@@ -2165,7 +2165,7 @@ pub mod options {
                 } => {
                     packet.clear_rpl_target_flags();
                     packet.set_rpl_target_prefix_length(*prefix_length);
-                    packet.set_rpl_target_prefix(prefix.as_bytes());
+                    packet.set_rpl_target_prefix(&prefix.octets());
                 }
                 Repr::TransitInformation {
                     external,
@@ -2616,7 +2616,7 @@ mod tests {
                 prefix,
             } => {
                 assert_eq!(prefix_length, 128);
-                assert_eq!(prefix.as_bytes(), &target_prefix[..]);
+                assert_eq!(prefix.octets(), target_prefix);
             }
             _ => unreachable!(),
         }
@@ -2707,9 +2707,7 @@ mod tests {
                 assert_eq!(status, 0x0);
                 assert_eq!(
                     dodag_id,
-                    Some(Ipv6Address([
-                        254, 128, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 1
-                    ]))
+                    Some(Ipv6Address::new(0xfe80, 0, 0, 0, 0x0200, 0, 0, 1))
                 );
             }
             _ => unreachable!(),

+ 8 - 8
src/wire/sixlowpan/iphc.rs

@@ -6,7 +6,7 @@
 use super::{
     AddressContext, AddressMode, Error, NextHeader, Result, UnresolvedAddress, DISPATCH_IPHC_HEADER,
 };
-use crate::wire::{ieee802154::Address as LlAddress, ipv6, IpProtocol};
+use crate::wire::{ieee802154::Address as LlAddress, ipv6, ipv6::AddressExt, IpProtocol};
 use byteorder::{ByteOrder, NetworkEndian};
 
 mod field {
@@ -526,7 +526,7 @@ impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
     ) -> usize {
         self.set_cid_field(0);
         self.set_sac_field(0);
-        let src = src_addr.as_bytes();
+        let src = src_addr.octets();
         if src_addr == ipv6::Address::UNSPECIFIED {
             self.set_sac_field(1);
             self.set_sam_field(0b00);
@@ -574,7 +574,7 @@ impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
         } else {
             // We cannot elide anything.
             self.set_sam_field(0b00);
-            self.set_field(idx, src);
+            self.set_field(idx, &src);
             idx += 16;
         }
 
@@ -593,7 +593,7 @@ impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
         self.set_dac_field(0);
         self.set_dam_field(0);
         self.set_m_field(0);
-        let dst = dst_addr.as_bytes();
+        let dst = dst_addr.octets();
         if dst_addr.is_multicast() {
             self.set_m_field(1);
 
@@ -619,7 +619,7 @@ impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
             } else {
                 self.set_dam_field(0b11);
 
-                self.set_field(idx, dst);
+                self.set_field(idx, &dst);
                 idx += 16;
             }
         } else if dst_addr.is_link_local() {
@@ -653,7 +653,7 @@ impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
         } else {
             self.set_dam_field(0b00);
 
-            self.set_field(idx, dst);
+            self.set_field(idx, &dst);
             idx += 16;
         }
 
@@ -771,7 +771,7 @@ impl Repr {
         len += if self.src_addr == ipv6::Address::UNSPECIFIED {
             0
         } else if self.src_addr.is_link_local() {
-            let src = self.src_addr.as_bytes();
+            let src = self.src_addr.octets();
             let ll = [src[14], src[15]];
 
             let is_eui_64 = self
@@ -799,7 +799,7 @@ impl Repr {
         };
 
         // Add the size of the destination header
-        let dst = self.dst_addr.as_bytes();
+        let dst = self.dst_addr.octets();
         len += if self.dst_addr.is_multicast() {
             if dst[1] == 0x02 && dst[2..15] == [0; 13] {
                 1

+ 1 - 0
src/wire/sixlowpan/mod.rs

@@ -6,6 +6,7 @@
 use super::{Error, Result};
 use crate::wire::ieee802154::Address as LlAddress;
 use crate::wire::ipv6;
+use crate::wire::ipv6::AddressExt;
 use crate::wire::IpProtocol;
 
 pub mod frag;

+ 2 - 2
src/wire/sixlowpan/nhc.rs

@@ -862,8 +862,8 @@ mod test {
 
         let payload = b"Hello World!";
 
-        let src_addr = ipv6::Address::default();
-        let dst_addr = ipv6::Address::default();
+        let src_addr = ipv6::Address::UNSPECIFIED;
+        let dst_addr = ipv6::Address::UNSPECIFIED;
 
         let len = udp.header_len() + payload.len();
         let mut buffer = [0u8; 127];

+ 3 - 3
src/wire/tcp.rs

@@ -1,5 +1,5 @@
 use byteorder::{ByteOrder, NetworkEndian};
-use core::{cmp, fmt, i32, ops};
+use core::{cmp, fmt, ops};
 
 use super::{Error, Result};
 use crate::phy::ChecksumCapabilities;
@@ -1192,9 +1192,9 @@ mod test {
     use crate::wire::Ipv4Address;
 
     #[cfg(feature = "proto-ipv4")]
-    const SRC_ADDR: Ipv4Address = Ipv4Address([192, 168, 1, 1]);
+    const SRC_ADDR: Ipv4Address = Ipv4Address::new(192, 168, 1, 1);
     #[cfg(feature = "proto-ipv4")]
-    const DST_ADDR: Ipv4Address = Ipv4Address([192, 168, 1, 2]);
+    const DST_ADDR: Ipv4Address = Ipv4Address::new(192, 168, 1, 2);
 
     #[cfg(feature = "proto-ipv4")]
     static PACKET_BYTES: [u8; 28] = [

+ 2 - 2
src/wire/udp.rs

@@ -354,9 +354,9 @@ mod test {
     use crate::wire::Ipv4Address;
 
     #[cfg(feature = "proto-ipv4")]
-    const SRC_ADDR: Ipv4Address = Ipv4Address([192, 168, 1, 1]);
+    const SRC_ADDR: Ipv4Address = Ipv4Address::new(192, 168, 1, 1);
     #[cfg(feature = "proto-ipv4")]
-    const DST_ADDR: Ipv4Address = Ipv4Address([192, 168, 1, 2]);
+    const DST_ADDR: Ipv4Address = Ipv4Address::new(192, 168, 1, 2);
 
     #[cfg(feature = "proto-ipv4")]
     static PACKET_BYTES: [u8; 12] = [