1 use core::net::Ipv4Addr; 2 3 use crate::{ArpHardwareId, EtherType}; 4 5 use super::{ArpOperation, ArpPacket}; 6 7 /// An ethernet & IPv4 "Address Resolution Protocol" Packet (a specific 8 /// version of [`crate::ArpPacket`]). 9 #[derive(Clone, Debug, PartialEq, Eq, Hash)] 10 pub struct ArpEthIpv4Packet { 11 /// Specifies the operation that the sender is performing. 12 pub operation: ArpOperation, 13 14 /// Sender MAC address. 15 pub sender_mac: [u8; 6], 16 17 /// Sender IPv4 address. 18 pub sender_ipv4: [u8; 4], 19 20 /// Sender MAC address. 21 pub target_mac: [u8; 6], 22 23 /// Target IPv4 address. 24 pub target_ipv4: [u8; 4], 25 } 26 27 impl ArpEthIpv4Packet { 28 /// Number of octets/bytes of the serialized packet. 29 pub const LEN: usize = 8 + 6 * 2 + 4 * 2; 30 31 /// Sender IPv4 address as [`core::net::Ipv4Addr`]. 32 #[inline] sender_ipv4_addr(&self) -> Ipv4Addr33 pub const fn sender_ipv4_addr(&self) -> Ipv4Addr { 34 Ipv4Addr::new( 35 self.sender_ipv4[0], 36 self.sender_ipv4[1], 37 self.sender_ipv4[2], 38 self.sender_ipv4[3], 39 ) 40 } 41 42 /// Target IPv4 address as [`core::net::Ipv4Addr`]. 43 #[inline] target_ipv4_addr(&self) -> Ipv4Addr44 pub const fn target_ipv4_addr(&self) -> Ipv4Addr { 45 Ipv4Addr::new( 46 self.target_ipv4[0], 47 self.target_ipv4[1], 48 self.target_ipv4[2], 49 self.target_ipv4[3], 50 ) 51 } 52 53 /// Returns the serialized header. to_bytes(&self) -> [u8; Self::LEN]54 pub const fn to_bytes(&self) -> [u8; Self::LEN] { 55 const ETH_HW_TYPE: [u8; 2] = ArpHardwareId::ETHERNET.0.to_be_bytes(); 56 const IPV4_ETH_TYPE: [u8; 2] = EtherType::IPV4.0.to_be_bytes(); 57 let op = self.operation.0.to_be_bytes(); 58 [ 59 ETH_HW_TYPE[0], 60 ETH_HW_TYPE[1], 61 IPV4_ETH_TYPE[0], 62 IPV4_ETH_TYPE[1], 63 6, 64 4, 65 op[0], 66 op[1], 67 self.sender_mac[0], 68 self.sender_mac[1], 69 self.sender_mac[2], 70 self.sender_mac[3], 71 self.sender_mac[4], 72 self.sender_mac[5], 73 self.sender_ipv4[0], 74 self.sender_ipv4[1], 75 self.sender_ipv4[2], 76 self.sender_ipv4[3], 77 self.target_mac[0], 78 self.target_mac[1], 79 self.target_mac[2], 80 self.target_mac[3], 81 self.target_mac[4], 82 self.target_mac[5], 83 self.target_ipv4[0], 84 self.target_ipv4[1], 85 self.target_ipv4[2], 86 self.target_ipv4[3], 87 ] 88 } 89 90 /// Converts the packet to generic arp packet. 91 #[inline] to_arp_packet(&self) -> ArpPacket92 pub const fn to_arp_packet(&self) -> ArpPacket { 93 // SAFETY: This is safe as 94 // * Both the hardware addresses have matching length 6 which is bellow the max of 255. 95 // * Both the protocol addresses have matching length 6 which is bellow the max of 255. 96 unsafe { 97 ArpPacket::new_unchecked( 98 ArpHardwareId::ETHERNET, 99 EtherType::IPV4, 100 self.operation, 101 &self.sender_mac, 102 &self.sender_ipv4, 103 &self.target_mac, 104 &self.target_ipv4, 105 ) 106 } 107 } 108 } 109 110 impl From<ArpEthIpv4Packet> for ArpPacket { from(value: ArpEthIpv4Packet) -> Self111 fn from(value: ArpEthIpv4Packet) -> Self { 112 value.to_arp_packet() 113 } 114 } 115 116 impl TryFrom<ArpPacket> for ArpEthIpv4Packet { 117 type Error = crate::err::arp::ArpEthIpv4FromError; 118 try_from(value: ArpPacket) -> Result<Self, Self::Error>119 fn try_from(value: ArpPacket) -> Result<Self, Self::Error> { 120 value.try_eth_ipv4() 121 } 122 } 123 124 #[cfg(test)] 125 mod tests { 126 use super::*; 127 use crate::test_gens::*; 128 use proptest::prelude::*; 129 130 proptest! { 131 #[test] 132 fn sender_ipv4_addr( 133 arp in arp_eth_ipv4_packet_any() 134 ) { 135 assert_eq!( 136 arp.sender_ipv4_addr(), 137 Ipv4Addr::new( 138 arp.sender_ipv4[0], 139 arp.sender_ipv4[1], 140 arp.sender_ipv4[2], 141 arp.sender_ipv4[3] 142 ) 143 ) 144 } 145 } 146 147 proptest! { 148 #[test] 149 fn target_ipv4_addr( 150 arp in arp_eth_ipv4_packet_any() 151 ) { 152 assert_eq!( 153 arp.target_ipv4_addr(), 154 Ipv4Addr::new( 155 arp.target_ipv4[0], 156 arp.target_ipv4[1], 157 arp.target_ipv4[2], 158 arp.target_ipv4[3] 159 ) 160 ) 161 } 162 } 163 164 proptest! { 165 #[test] 166 fn to_bytes( 167 arp in arp_eth_ipv4_packet_any() 168 ) { 169 assert_eq!( 170 &arp.to_bytes()[..], 171 &arp.to_arp_packet().to_bytes()[..] 172 ); 173 } 174 } 175 176 proptest! { 177 #[test] 178 fn to_arp_packet( 179 arp in arp_eth_ipv4_packet_any() 180 ) { 181 let actual = arp.to_arp_packet(); 182 assert_eq!(ArpHardwareId::ETHERNET, actual.hw_addr_type); 183 assert_eq!(EtherType::IPV4, actual.proto_addr_type); 184 assert_eq!(6, actual.hw_addr_size()); 185 assert_eq!(4, actual.protocol_addr_size()); 186 assert_eq!(&arp.target_mac[..], actual.target_hw_addr()); 187 assert_eq!(&arp.target_ipv4[..], actual.target_protocol_addr()); 188 assert_eq!(&arp.sender_mac[..], actual.sender_hw_addr()); 189 assert_eq!(&arp.sender_ipv4[..], actual.sender_protocol_addr()); 190 } 191 } 192 193 proptest! { 194 #[test] 195 fn into_arp_packet( 196 arp in arp_eth_ipv4_packet_any() 197 ) { 198 let actual = ArpPacket::from(arp.clone()); 199 assert_eq!(actual, arp.to_arp_packet()); 200 } 201 } 202 203 proptest! { 204 #[test] 205 fn try_from_arp_packet( 206 arp in arp_packet_any() 207 ) { 208 let actual = ArpEthIpv4Packet::try_from(arp.clone()); 209 assert_eq!(actual, arp.clone().try_eth_ipv4()); 210 } 211 } 212 } 213