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::fmt; 9 use std::io; 10 use std::str::FromStr; 11 12 use serde::de::{Deserialize, Deserializer, Error}; 13 use serde::ser::{Serialize, Serializer}; 14 15 pub const MAC_ADDR_LEN: usize = 6; 16 17 #[derive(Clone, Copy, Debug, PartialEq, Eq)] 18 pub struct MacAddr { 19 bytes: [u8; MAC_ADDR_LEN], 20 } 21 22 impl MacAddr { 23 pub fn parse_str<S>(s: &S) -> Result<MacAddr, io::Error> 24 where 25 S: AsRef<str> + ?Sized, 26 { 27 let v: Vec<&str> = s.as_ref().split(':').collect(); 28 let mut bytes = [0u8; MAC_ADDR_LEN]; 29 let common_err = Err(io::Error::new( 30 io::ErrorKind::Other, 31 format!("parsing of {} into a MAC address failed", s.as_ref()), 32 )); 33 34 if v.len() != MAC_ADDR_LEN { 35 return common_err; 36 } 37 38 for i in 0..MAC_ADDR_LEN { 39 if v[i].len() != 2 { 40 return common_err; 41 } 42 bytes[i] = u8::from_str_radix(v[i], 16).map_err(|e| { 43 io::Error::new( 44 io::ErrorKind::Other, 45 format!("parsing of {} into a MAC address failed: {}", s.as_ref(), 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::new( 69 io::ErrorKind::Other, 70 format!("invalid length of slice: {} vs {}", src.len(), MAC_ADDR_LEN), 71 )); 72 } 73 Ok(MacAddr::from_bytes_unchecked(src)) 74 } 75 76 #[inline] 77 pub fn get_bytes(&self) -> &[u8] { 78 &self.bytes 79 } 80 81 pub fn local_random() -> MacAddr { 82 // Generate a fully random MAC 83 let mut random_bytes = [0u8; MAC_ADDR_LEN]; 84 if let Err(e) = getrandom::getrandom(&mut random_bytes) { 85 error!( 86 "Error populating MAC address with random data: {}", 87 e.to_string() 88 ); 89 } 90 91 // Set the first byte to make the OUI a locally administered OUI 92 random_bytes[0] = 0x2e; 93 94 MacAddr { 95 bytes: random_bytes, 96 } 97 } 98 } 99 100 impl fmt::Display for MacAddr { 101 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 102 let b = &self.bytes; 103 write!( 104 f, 105 "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}", 106 b[0], b[1], b[2], b[3], b[4], b[5] 107 ) 108 } 109 } 110 111 impl Serialize for MacAddr { 112 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> 113 where 114 S: Serializer, 115 { 116 self.to_string().serialize(serializer) 117 } 118 } 119 120 impl<'de> Deserialize<'de> for MacAddr { 121 fn deserialize<D>(deserializer: D) -> Result<MacAddr, D::Error> 122 where 123 D: Deserializer<'de>, 124 { 125 let s = String::deserialize(deserializer)?; 126 MacAddr::parse_str(&s) 127 .map_err(|e| D::Error::custom(format!("The provided MAC address is invalid: {e}"))) 128 } 129 } 130 131 pub enum MacAddrParseError { 132 InvalidValue(String), 133 } 134 135 impl FromStr for MacAddr { 136 type Err = MacAddrParseError; 137 138 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> { 139 MacAddr::parse_str(s).map_err(|_| MacAddrParseError::InvalidValue(s.to_owned())) 140 } 141 } 142 143 #[cfg(test)] 144 mod tests { 145 use super::*; 146 147 #[test] 148 fn test_mac_addr() { 149 // too long 150 assert!(MacAddr::parse_str("aa:aa:aa:aa:aa:aa:aa").is_err()); 151 152 // invalid hex 153 assert!(MacAddr::parse_str("aa:aa:aa:aa:aa:ax").is_err()); 154 155 // single digit mac address component should be invalid 156 assert!(MacAddr::parse_str("aa:aa:aa:aa:aa:b").is_err()); 157 158 // components with more than two digits should also be invalid 159 assert!(MacAddr::parse_str("aa:aa:aa:aa:aa:bbb").is_err()); 160 161 let mac = MacAddr::parse_str("12:34:56:78:9a:BC").unwrap(); 162 163 println!("parsed MAC address: {mac}"); 164 165 let bytes = mac.get_bytes(); 166 assert_eq!(bytes, [0x12u8, 0x34, 0x56, 0x78, 0x9a, 0xbc]); 167 } 168 169 #[test] 170 fn test_from_bytes() { 171 let src1 = [0x01, 0x02, 0x03, 0x04, 0x05]; 172 let src2 = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06]; 173 let src3 = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07]; 174 175 assert!(MacAddr::from_bytes(&src1[..]).is_err()); 176 177 let x = MacAddr::from_bytes(&src2[..]).unwrap(); 178 assert_eq!(x.to_string(), String::from("01:02:03:04:05:06")); 179 180 assert!(MacAddr::from_bytes(&src3[..]).is_err()); 181 } 182 183 #[test] 184 fn test_mac_addr_serialization_and_deserialization() { 185 let mac: MacAddr = 186 serde_json::from_str("\"12:34:56:78:9a:bc\"").expect("MacAddr deserialization failed."); 187 188 let bytes = mac.get_bytes(); 189 assert_eq!(bytes, [0x12u8, 0x34, 0x56, 0x78, 0x9a, 0xbc]); 190 191 let s = serde_json::to_string(&mac).expect("MacAddr serialization failed."); 192 assert_eq!(s, "\"12:34:56:78:9a:bc\""); 193 } 194 } 195