1 // Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 // SPDX-License-Identifier: Apache-2.0 3 // 4 // Portions Copyright 2017 The Chromium OS Authors. All rights reserved. 5 // Use of this source code is governed by a BSD-style license that can be 6 // found in the THIRD-PARTY file. 7 8 use std::str::FromStr; 9 use std::{fmt, io}; 10 11 use serde::de::{Deserialize, Deserializer, Error}; 12 use serde::ser::{Serialize, Serializer}; 13 14 pub const MAC_ADDR_LEN: usize = 6; 15 16 #[derive(Clone, Copy, Debug, PartialEq, Eq)] 17 pub struct MacAddr { 18 bytes: [u8; MAC_ADDR_LEN], 19 } 20 21 impl MacAddr { 22 pub fn parse_str<S>(s: &S) -> Result<MacAddr, io::Error> 23 where 24 S: AsRef<str> + ?Sized, 25 { 26 let v: Vec<&str> = s.as_ref().split(':').collect(); 27 let mut bytes = [0u8; MAC_ADDR_LEN]; 28 let common_err = Err(io::Error::other(format!( 29 "parsing of {} into a MAC address failed", 30 s.as_ref() 31 ))); 32 33 if v.len() != MAC_ADDR_LEN { 34 return common_err; 35 } 36 37 for i in 0..MAC_ADDR_LEN { 38 if v[i].len() != 2 { 39 return common_err; 40 } 41 bytes[i] = u8::from_str_radix(v[i], 16).map_err(|e| { 42 io::Error::other(format!( 43 "parsing of {} into a MAC address failed: {}", 44 s.as_ref(), 45 e 46 )) 47 })?; 48 } 49 50 Ok(MacAddr { bytes }) 51 } 52 53 // Does not check whether src.len() == MAC_ADDR_LEN. 54 #[inline] 55 pub fn from_bytes_unchecked(src: &[u8]) -> MacAddr { 56 // TODO: using something like std::mem::uninitialized could avoid the extra initialization, 57 // if this ever becomes a performance bottleneck. 58 let mut bytes = [0u8; MAC_ADDR_LEN]; 59 bytes[..].copy_from_slice(src); 60 61 MacAddr { bytes } 62 } 63 64 // An error can only occur if the slice length is different from MAC_ADDR_LEN. 65 #[inline] 66 pub fn from_bytes(src: &[u8]) -> Result<MacAddr, io::Error> { 67 if src.len() != MAC_ADDR_LEN { 68 return Err(io::Error::other(format!( 69 "invalid length of slice: {} vs {}", 70 src.len(), 71 MAC_ADDR_LEN 72 ))); 73 } 74 Ok(MacAddr::from_bytes_unchecked(src)) 75 } 76 77 #[inline] 78 pub fn get_bytes(&self) -> &[u8] { 79 &self.bytes 80 } 81 82 pub fn local_random() -> MacAddr { 83 // Generate a fully random MAC 84 let mut random_bytes = [0u8; MAC_ADDR_LEN]; 85 if let Err(e) = getrandom::fill(&mut random_bytes) { 86 error!( 87 "Error populating MAC address with random data: {}", 88 e.to_string() 89 ); 90 } 91 92 // Set the first byte to make the OUI a locally administered OUI 93 random_bytes[0] = 0x2e; 94 95 MacAddr { 96 bytes: random_bytes, 97 } 98 } 99 } 100 101 impl fmt::Display for MacAddr { 102 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 103 let b = &self.bytes; 104 write!( 105 f, 106 "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}", 107 b[0], b[1], b[2], b[3], b[4], b[5] 108 ) 109 } 110 } 111 112 impl Serialize for MacAddr { 113 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> 114 where 115 S: Serializer, 116 { 117 self.to_string().serialize(serializer) 118 } 119 } 120 121 impl<'de> Deserialize<'de> for MacAddr { 122 fn deserialize<D>(deserializer: D) -> Result<MacAddr, D::Error> 123 where 124 D: Deserializer<'de>, 125 { 126 let s = String::deserialize(deserializer)?; 127 MacAddr::parse_str(&s) 128 .map_err(|e| D::Error::custom(format!("The provided MAC address is invalid: {e}"))) 129 } 130 } 131 132 pub enum MacAddrParseError { 133 InvalidValue(String), 134 } 135 136 impl FromStr for MacAddr { 137 type Err = MacAddrParseError; 138 139 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> { 140 MacAddr::parse_str(s).map_err(|_| MacAddrParseError::InvalidValue(s.to_owned())) 141 } 142 } 143 144 #[cfg(test)] 145 mod tests { 146 use super::*; 147 148 #[test] 149 fn test_mac_addr() { 150 // too long 151 MacAddr::parse_str("aa:aa:aa:aa:aa:aa:aa").unwrap_err(); 152 153 // invalid hex 154 MacAddr::parse_str("aa:aa:aa:aa:aa:ax").unwrap_err(); 155 156 // single digit mac address component should be invalid 157 MacAddr::parse_str("aa:aa:aa:aa:aa:b").unwrap_err(); 158 159 // components with more than two digits should also be invalid 160 MacAddr::parse_str("aa:aa:aa:aa:aa:bbb").unwrap_err(); 161 162 let mac = MacAddr::parse_str("12:34:56:78:9a:BC").unwrap(); 163 164 println!("parsed MAC address: {mac}"); 165 166 let bytes = mac.get_bytes(); 167 assert_eq!(bytes, [0x12u8, 0x34, 0x56, 0x78, 0x9a, 0xbc]); 168 } 169 170 #[test] 171 fn test_from_bytes() { 172 let src1 = [0x01, 0x02, 0x03, 0x04, 0x05]; 173 let src2 = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06]; 174 let src3 = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07]; 175 176 MacAddr::from_bytes(&src1[..]).unwrap_err(); 177 178 let x = MacAddr::from_bytes(&src2[..]).unwrap(); 179 assert_eq!(x.to_string(), String::from("01:02:03:04:05:06")); 180 181 MacAddr::from_bytes(&src3[..]).unwrap_err(); 182 } 183 184 #[test] 185 fn test_mac_addr_serialization_and_deserialization() { 186 let mac: MacAddr = 187 serde_json::from_str("\"12:34:56:78:9a:bc\"").expect("MacAddr deserialization failed."); 188 189 let bytes = mac.get_bytes(); 190 assert_eq!(bytes, [0x12u8, 0x34, 0x56, 0x78, 0x9a, 0xbc]); 191 192 let s = serde_json::to_string(&mac).expect("MacAddr serialization failed."); 193 assert_eq!(s, "\"12:34:56:78:9a:bc\""); 194 } 195 } 196