Browse Source

wire: use core::net::Ipv4Addr as the ipv4 address type.

Dario Nieuwenhuis 6 months ago
parent
commit
e6b9a9ca2a

+ 1 - 1
Cargo.toml

@@ -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"
 

+ 4 - 4
benches/bench.rs

@@ -22,9 +22,9 @@ mod wire {
     ]));
 
     #[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 +84,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,

+ 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();

+ 4 - 4
src/iface/fragmentation.rs

@@ -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,

+ 20 - 15
src/iface/interface/mod.rs

@@ -830,7 +830,7 @@ 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,
             #[cfg(feature = "proto-ipv6")]
@@ -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.as_bytes();
+                        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

+ 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,

+ 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.

+ 7 - 7
src/iface/route.rs

@@ -200,17 +200,17 @@ mod test {
     #[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)
         }
     }
 

+ 7 - 37
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};
 
@@ -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,16 +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 = ();
@@ -526,26 +516,6 @@ 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() {
@@ -630,7 +600,7 @@ mod test {
         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 +624,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(())),

+ 9 - 8
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;
@@ -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]);
 

+ 1 - 1
src/socket/dns.rs

@@ -28,7 +28,7 @@ const MDNS_IPV6_ADDR: IpAddress = IpAddress::Ipv6(crate::wire::Ipv6Address([
 
 #[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)]

+ 3 - 3
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(()));

+ 2 - 2
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,

+ 21 - 11
src/socket/tcp.rs

@@ -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,11 +2596,20 @@ 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;
@@ -2625,6 +2626,15 @@ mod test {
             ]);
 
             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,
+            };
         }
     }
 

+ 21 - 11
src/socket/udp.rs

@@ -619,9 +619,18 @@ 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;
@@ -636,17 +645,18 @@ mod test {
             const OTHER_ADDR: IpvXAddress = IpvXAddress([
                 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 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());
             }
         }
     }

+ 20 - 20
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;
@@ -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

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

+ 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.

+ 5 - 22
src/wire/ip.rs

@@ -4,7 +4,7 @@ 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};
 
@@ -127,16 +127,6 @@ 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 {
@@ -193,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),
         }
     }
 }
@@ -224,13 +214,6 @@ impl From<::core::net::Ipv6Addr> for Address {
     }
 }
 
-#[cfg(feature = "proto-ipv4")]
-impl From<Ipv4Address> for Address {
-    fn from(addr: Ipv4Address) -> Self {
-        Address::Ipv4(addr)
-    }
-}
-
 #[cfg(feature = "proto-ipv6")]
 impl From<Ipv6Address> for Address {
     fn from(addr: Ipv6Address) -> Self {
@@ -758,8 +741,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[..]),
         ])
     }

+ 129 - 220
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,89 +41,42 @@ 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
-    }
+    fn is_unicast(&self) -> bool;
 
-    /// Query whether the address falls into the "link-local" range.
-    pub fn is_link_local(&self) -> bool {
-        self.0[0..2] == [169, 254]
-    }
+    /// 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 address falls into the "loopback" range.
-    pub const fn is_loopback(&self) -> bool {
-        self.0[0] == 127
+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))
     }
 
-    /// Convert to an `IpAddress`.
-    ///
-    /// Same as `.into()`, but works in `const`.
-    pub const fn into_address(self) -> super::IpAddress {
-        super::IpAddress::Ipv4(self)
+    /// Query whether the address is an unicast address.
+    fn is_unicast(&self) -> bool {
+        !(self.is_broadcast() || self.is_multicast() || self.is_unspecified())
     }
 
-    /// 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> {
+    fn prefix_len(&self) -> Option<u8> {
         let mut ones = true;
         let mut prefix_len = 0;
-        for byte in self.as_bytes() {
+        for byte in self.octets() {
             let mut mask = 0x80;
             for _ in 0..8 {
-                let one = *byte & mask != 0;
+                let one = byte & mask != 0;
                 if ones {
                     // Expect 1s until first 0
                     if one {
@@ -136,42 +95,9 @@ impl Address {
     }
 }
 
-impl From<::core::net::Ipv4Addr> for Address {
-    fn from(x: ::core::net::Ipv4Addr) -> Address {
-        Address(x.octets())
-    }
-}
-
-impl From<Address> for ::core::net::Ipv4Addr {
-    fn from(Address(x): Address) -> ::core::net::Ipv4Addr {
-        x.into()
-    }
-}
-
-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])
-    }
-}
-
-#[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]
-        )
-    }
-}
-
 /// 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,
@@ -192,7 +118,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,
@@ -216,18 +142,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.
@@ -238,29 +157,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,
         }
     }
@@ -268,15 +173,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
@@ -602,14 +500,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.
@@ -821,13 +719,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;
 
@@ -853,8 +751,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[..]);
     }
@@ -875,8 +773,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[..]);
@@ -916,8 +814,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,
@@ -1043,124 +941,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
         );
     }
@@ -1168,44 +1077,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)
         );
     }
 }

+ 6 - 8
src/wire/ipv6.rs

@@ -6,7 +6,7 @@ use core::fmt;
 use super::{Error, Result};
 use crate::wire::ip::pretty_print_ip_payload;
 #[cfg(feature = "proto-ipv4")]
-use crate::wire::ipv4;
+use crate::wire::{Ipv4Address, Ipv4AddressExt};
 
 pub use super::IpProtocol as Protocol;
 
@@ -246,11 +246,9 @@ impl Address {
 
     #[cfg(feature = "proto-ipv4")]
     /// Convert an IPv4 mapped IPv6 address to an IPv4 address.
-    pub fn as_ipv4(&self) -> Option<ipv4::Address> {
+    pub fn as_ipv4(&self) -> Option<Ipv4Address> {
         if self.is_ipv4_mapped() {
-            Some(ipv4::Address::from_bytes(
-                &self.0[IPV4_MAPPED_PREFIX_SIZE..],
-            ))
+            Some(Ipv4Address::from_bytes(&self.0[IPV4_MAPPED_PREFIX_SIZE..]))
         } else {
             None
         }
@@ -474,11 +472,11 @@ impl defmt::Format for Address {
 
 #[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 {
+impl From<Ipv4Address> for Address {
+    fn from(address: Ipv4Address) -> 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);
+        b[Self::IPV4_MAPPED_PREFIX.len()..].copy_from_slice(&address.octets());
         Self(b)
     }
 }

+ 5 - 0
src/wire/mod.rs

@@ -188,8 +188,13 @@ 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-ipv4")]
+pub(crate) use self::ipv4::AddressExt as Ipv4AddressExt;
+
 #[cfg(feature = "proto-ipv6")]
 pub(crate) use self::ipv6::MulticastScope as Ipv6MulticastScope;
 #[cfg(feature = "proto-ipv6")]

+ 2 - 2
src/wire/tcp.rs

@@ -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] = [