libwifi/frame/components/
mac_address.rs1use std::fmt;
2use std::hash::Hash;
3
4use rand::{Rng, RngCore, rng};
5
6#[derive(Clone, Debug, Hash, Eq, PartialEq, Copy, Ord, PartialOrd)]
17pub struct MacAddress(pub [u8; 6]);
18
19impl MacAddress {
20 pub fn from_vec(vec: Vec<u8>) -> Option<MacAddress> {
21 if vec.len() == 6 {
22 let mut arr = [0u8; 6];
23 for (place, element) in arr.iter_mut().zip(vec.iter()) {
24 *place = *element;
25 }
26 Some(MacAddress(arr))
27 } else {
28 None
30 }
31 }
32
33 pub fn to_u64(&self) -> u64 {
35 let bytes = self.0;
36 ((bytes[0] as u64) << 40)
37 | ((bytes[1] as u64) << 32)
38 | ((bytes[2] as u64) << 24)
39 | ((bytes[3] as u64) << 16)
40 | ((bytes[4] as u64) << 8)
41 | (bytes[5] as u64)
42 }
43
44 pub fn to_long_string(&self) -> String {
46 format!(
47 "{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
48 self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5],
49 )
50 }
51
52 pub fn random() -> Self {
54 loop {
55 let mac = MacAddress(generate_random_bytes(6).try_into().unwrap());
56 if mac.is_real_device() {
57 return mac;
58 }
59 }
60 }
61
62 pub fn broadcast() -> Self {
63 MacAddress([255, 255, 255, 255, 255, 255])
64 }
65
66 pub fn zeroed() -> Self {
67 MacAddress([0, 0, 0, 0, 0, 0])
68 }
69
70 pub fn random_with_oui(other: &MacAddress) -> Self {
72 let mut rng = rand::rng();
73 let mut new_mac = other.0;
74 new_mac[3..6].fill_with(|| rng.random());
75 MacAddress(new_mac)
76 }
77
78 pub fn encode(&self) -> [u8; 6] {
80 self.0
81 }
82
83 pub fn is_private(&self) -> bool {
85 self.0[0] & 0x02 != 0
86 }
87
88 pub fn is_mcast(&self) -> bool {
90 self.0[0] % 2 == 1
91 }
92
93 pub fn is_broadcast(&self) -> bool {
95 self.0 == [255, 255, 255, 255, 255, 255]
96 }
97
98 pub fn is_groupcast(&self) -> bool {
101 self.0[0] == 1 && self.0[1] == 128 && self.0[2] == 194
102 }
103
104 pub fn is_ipv4_multicast(&self) -> bool {
106 self.0[0] == 1 && self.0[1] == 0 && self.0[2] == 94
107 }
108
109 pub fn is_ipv6_neighborhood_discovery(&self) -> bool {
111 self.0 == [51, 51, 0, 0, 0, 0]
112 }
113
114 pub fn is_ipv6_multicast(&self) -> bool {
116 self.0[0] == 51 && self.0[1] == 51
117 }
118
119 pub fn is_spanning_tree(&self) -> bool {
121 self.0[0] == 1 && self.0[1] == 128 && self.0[2] == 194
122 }
123
124 pub fn is_real_device(&self) -> bool {
129 !(self.is_ipv6_multicast()
130 || self.is_broadcast()
131 || self.is_ipv4_multicast()
132 || self.is_groupcast()
133 || self.is_spanning_tree()
134 || self.is_mcast())
135 }
136}
137
138impl fmt::Display for MacAddress {
139 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
140 write!(
141 f,
142 "{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
143 self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5],
144 )
145 }
146}
147
148#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
149pub enum MacParseError {
150 InvalidDigit,
151 InvalidLength,
152}
153
154impl fmt::Display for MacParseError {
155 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
156 write!(f, "Encountered an error while parsing a mac address.")
157 }
158}
159
160impl std::error::Error for MacParseError {}
161
162impl std::str::FromStr for MacAddress {
180 type Err = MacParseError;
181
182 fn from_str(input: &str) -> Result<Self, Self::Err> {
183 let mut array = [0u8; 6];
184
185 let input_lower = input.to_lowercase();
186 let bytes: Vec<&str> = if input_lower.contains(':') {
188 input_lower.split(':').collect()
189 } else if input.contains('-') {
190 input_lower.split('-').collect()
191 } else if input_lower.len() == 12 {
192 input_lower
194 .as_bytes()
195 .chunks(2)
196 .map(|chunk| std::str::from_utf8(chunk).unwrap_or(""))
197 .collect()
198 } else {
199 return Err(MacParseError::InvalidLength);
200 };
201
202 if bytes.len() != 6 {
204 return Err(MacParseError::InvalidLength);
205 }
206
207 for (count, byte) in bytes.iter().enumerate() {
209 array[count] = u8::from_str_radix(byte, 16).map_err(|_| MacParseError::InvalidDigit)?;
210 }
211
212 Ok(MacAddress(array))
213 }
214}
215
216pub fn generate_random_bytes(x: usize) -> Vec<u8> {
217 let mut rng = rng();
218 let length = x;
219 let mut bytes = vec![0u8; length];
220 rng.fill_bytes(&mut bytes);
221 if !bytes.is_empty() {
223 bytes[0] &= 0xFE; }
225
226 bytes
227}
228
229#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
232pub struct MacAddressGlob {
233 pattern: [u8; 6],
234 mask: [u8; 6],
235}
236
237impl fmt::Display for MacAddressGlob {
238 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
239 for i in 0..6 {
240 if self.mask[i] == 0 {
241 write!(f, "*")?;
242 } else if self.mask[i] == 0xF0 {
243 write!(f, "{:x}*", self.pattern[i] >> 4)?;
244 } else {
245 write!(f, "{:02x}", self.pattern[i])?;
246 }
247 if i < 5 {
248 write!(f, ":")?;
249 }
250 }
251 Ok(())
252 }
253}
254
255pub enum MacGlobParseError {
256 InvalidDigit,
257 InvalidLength,
258}
259
260impl fmt::Display for MacGlobParseError {
261 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
262 match self {
263 MacGlobParseError::InvalidDigit => write!(f, "Invalid hex digit in pattern"),
264 MacGlobParseError::InvalidLength => write!(f, "Pattern is too long"),
265 }
266 }
267}
268
269impl MacAddressGlob {
270 pub fn new(pattern: &str) -> Result<Self, MacGlobParseError> {
271 let normalized_pattern = pattern.to_lowercase().replace(&[':', '-', '.'][..], "");
272
273 if normalized_pattern.len() > 12 {
274 return Err(MacGlobParseError::InvalidLength);
275 }
276
277 let mut pattern_bytes = [0u8; 6];
278 let mut mask_bytes = [0u8; 6];
279
280 for (i, chunk) in normalized_pattern.as_bytes().chunks(2).enumerate() {
281 if i >= 6 {
282 return Err(MacGlobParseError::InvalidLength);
283 }
284 let (pattern_byte, mask_byte) = match chunk {
285 [b'*'] => (0x00, 0x00),
286 [high, b'*'] => {
287 let high_nibble = match high {
288 b'0'..=b'9' => high - b'0',
289 b'a'..=b'f' => high - b'a' + 10,
290 _ => return Err(MacGlobParseError::InvalidDigit),
291 };
292 (high_nibble << 4, 0xF0)
293 }
294 [high, low] => {
295 let high_nibble = match high {
296 b'0'..=b'9' => high - b'0',
297 b'a'..=b'f' => high - b'a' + 10,
298 _ => return Err(MacGlobParseError::InvalidDigit),
299 };
300 let low_nibble = match low {
301 b'0'..=b'9' => low - b'0',
302 b'a'..=b'f' => low - b'a' + 10,
303 _ => return Err(MacGlobParseError::InvalidDigit),
304 };
305 ((high_nibble << 4) | low_nibble, 0xFF)
306 }
307 _ => return Err(MacGlobParseError::InvalidDigit),
308 };
309 pattern_bytes[i] = pattern_byte;
310 mask_bytes[i] = mask_byte;
311 }
312
313 for i in (normalized_pattern.len() / 2)..6 {
315 pattern_bytes[i] = 0x00;
316 mask_bytes[i] = 0x00;
317 }
318
319 Ok(Self {
320 pattern: pattern_bytes,
321 mask: mask_bytes,
322 })
323 }
324
325 pub fn from_mac_address(mac: &MacAddress) -> Self {
326 Self {
327 pattern: mac.0,
328 mask: [0xFF; 6],
329 }
330 }
331
332 pub fn matches(&self, mac: &MacAddress) -> bool {
333 for i in 0..6 {
334 if (mac.0[i] & self.mask[i]) != (self.pattern[i] & self.mask[i]) {
335 return false;
336 }
337 }
338 true
339 }
340}