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::new( 29 io::ErrorKind::Other, 30 format!("parsing of {} into a MAC address failed", 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::new( 43 io::ErrorKind::Other, 44 format!("parsing of {} into a MAC address failed: {}", s.as_ref(), e), 45 ) 46 })?; 47 } 48 49 Ok(MacAddr { bytes }) 50 } 51 52 // Does not check whether src.len() == MAC_ADDR_LEN. 53 #[inline] 54 pub fn from_bytes_unchecked(src: &[u8]) -> MacAddr { 55 // TODO: using something like std::mem::uninitialized could avoid the extra initialization, 56 // if this ever becomes a performance bottleneck. 57 let mut bytes = [0u8; MAC_ADDR_LEN]; 58 bytes[..].copy_from_slice(src); 59 60 MacAddr { bytes } 61 } 62 63 // An error can only occur if the slice length is different from MAC_ADDR_LEN. 64 #[inline] 65 pub fn from_bytes(src: &[u8]) -> Result<MacAddr, io::Error> { 66 if src.len() != MAC_ADDR_LEN { 67 return Err(io::Error::new( 68 io::ErrorKind::Other, 69 format!("invalid length of slice: {} vs {}", src.len(), MAC_ADDR_LEN), 70 )); 71 } 72 Ok(MacAddr::from_bytes_unchecked(src)) 73 } 74 75 #[inline] 76 pub fn get_bytes(&self) -> &[u8] { 77 &self.bytes 78 } 79 80 pub fn local_random() -> MacAddr { 81 // Generate a fully random MAC 82 let mut random_bytes = [0u8; MAC_ADDR_LEN]; 83 if let Err(e) = getrandom::getrandom(&mut random_bytes) { 84 error!( 85 "Error populating MAC address with random data: {}", 86 e.to_string() 87 ); 88 } 89 90 // Set the first byte to make the OUI a locally administered OUI 91 random_bytes[0] = 0x2e; 92 93 MacAddr { 94 bytes: random_bytes, 95 } 96 } 97 } 98 99 impl fmt::Display for MacAddr { 100 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 101 let b = &self.bytes; 102 write!( 103 f, 104 "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}", 105 b[0], b[1], b[2], b[3], b[4], b[5] 106 ) 107 } 108 } 109 110 impl Serialize for MacAddr { 111 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> 112 where 113 S: Serializer, 114 { 115 self.to_string().serialize(serializer) 116 } 117 } 118 119 impl<'de> Deserialize<'de> for MacAddr { 120 fn deserialize<D>(deserializer: D) -> Result<MacAddr, D::Error> 121 where 122 D: Deserializer<'de>, 123 { 124 let s = String::deserialize(deserializer)?; 125 MacAddr::parse_str(&s) 126 .map_err(|e| D::Error::custom(format!("The provided MAC address is invalid: {e}"))) 127 } 128 } 129 130 pub enum MacAddrParseError { 131 InvalidValue(String), 132 } 133 134 impl FromStr for MacAddr { 135 type Err = MacAddrParseError; 136 137 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> { 138 MacAddr::parse_str(s).map_err(|_| MacAddrParseError::InvalidValue(s.to_owned())) 139 } 140 } 141 142 #[cfg(test)] 143 mod tests { 144 use super::*; 145 146 #[test] 147 fn test_mac_addr() { 148 // too long 149 assert!(MacAddr::parse_str("aa:aa:aa:aa:aa:aa:aa").is_err()); 150 151 // invalid hex 152 assert!(MacAddr::parse_str("aa:aa:aa:aa:aa:ax").is_err()); 153 154 // single digit mac address component should be invalid 155 assert!(MacAddr::parse_str("aa:aa:aa:aa:aa:b").is_err()); 156 157 // components with more than two digits should also be invalid 158 assert!(MacAddr::parse_str("aa:aa:aa:aa:aa:bbb").is_err()); 159 160 let mac = MacAddr::parse_str("12:34:56:78:9a:BC").unwrap(); 161 162 println!("parsed MAC address: {mac}"); 163 164 let bytes = mac.get_bytes(); 165 assert_eq!(bytes, [0x12u8, 0x34, 0x56, 0x78, 0x9a, 0xbc]); 166 } 167 168 #[test] 169 fn test_from_bytes() { 170 let src1 = [0x01, 0x02, 0x03, 0x04, 0x05]; 171 let src2 = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06]; 172 let src3 = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07]; 173 174 assert!(MacAddr::from_bytes(&src1[..]).is_err()); 175 176 let x = MacAddr::from_bytes(&src2[..]).unwrap(); 177 assert_eq!(x.to_string(), String::from("01:02:03:04:05:06")); 178 179 assert!(MacAddr::from_bytes(&src3[..]).is_err()); 180 } 181 182 #[test] 183 fn test_mac_addr_serialization_and_deserialization() { 184 let mac: MacAddr = 185 serde_json::from_str("\"12:34:56:78:9a:bc\"").expect("MacAddr deserialization failed."); 186 187 let bytes = mac.get_bytes(); 188 assert_eq!(bytes, [0x12u8, 0x34, 0x56, 0x78, 0x9a, 0xbc]); 189 190 let s = serde_json::to_string(&mac).expect("MacAddr serialization failed."); 191 assert_eq!(s, "\"12:34:56:78:9a:bc\""); 192 } 193 } 194