• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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