2 * Copyright 2016 Facebook, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include <folly/MacAddress.h>
21 #include <folly/Exception.h>
22 #include <folly/IPAddressV6.h>
24 using std::invalid_argument;
29 const MacAddress MacAddress::BROADCAST{Endian::big(uint64_t(0xffffffffffffU))};
30 const MacAddress MacAddress::ZERO;
32 MacAddress::MacAddress(StringPiece str) {
33 memset(&bytes_, 0, 8);
37 MacAddress MacAddress::createMulticast(IPAddressV6 v6addr) {
38 // This method should only be used for multicast addresses.
39 DCHECK(v6addr.isMulticast());
44 memcpy(bytes + 2, v6addr.bytes() + 12, 4);
45 return fromBinary(ByteRange(bytes, SIZE));
48 string MacAddress::toString() const {
49 static const char hexValues[] = "0123456789abcdef";
52 result[0] = hexValues[getByte(0) >> 4];
53 result[1] = hexValues[getByte(0) & 0xf];
55 result[3] = hexValues[getByte(1) >> 4];
56 result[4] = hexValues[getByte(1) & 0xf];
58 result[6] = hexValues[getByte(2) >> 4];
59 result[7] = hexValues[getByte(2) & 0xf];
61 result[9] = hexValues[getByte(3) >> 4];
62 result[10] = hexValues[getByte(3) & 0xf];
64 result[12] = hexValues[getByte(4) >> 4];
65 result[13] = hexValues[getByte(4) & 0xf];
67 result[15] = hexValues[getByte(5) >> 4];
68 result[16] = hexValues[getByte(5) & 0xf];
72 void MacAddress::parse(StringPiece str) {
73 // Helper function to convert a single hex char into an integer
74 auto unhex = [](char c) -> int {
75 return c >= '0' && c <= '9' ? c - '0' :
76 c >= 'A' && c <= 'F' ? c - 'A' + 10 :
77 c >= 'a' && c <= 'f' ? c - 'a' + 10 :
80 auto isSeparatorChar = [](char c) {
81 return c == ':' || c == '-';
86 for (unsigned int byteIndex = 0; byteIndex < SIZE; ++byteIndex) {
88 throw invalid_argument(to<string>("invalid MAC address \"", str,
89 "\": not enough digits"));
92 // Skip over ':' or '-' separators between bytes
93 if (byteIndex != 0 && isSeparatorChar(*p)) {
96 throw invalid_argument(to<string>("invalid MAC address \"", str,
97 "\": not enough digits"));
101 // Parse the upper nibble
102 int upper = unhex(*p);
104 throw invalid_argument(to<string>("invalid MAC address \"", str,
105 "\": contains non-hex digit"));
109 // Parse the lower nibble
111 if (p == str.end()) {
117 // Also accept ':', '-', or '\0', to handle the case where one
118 // of the bytes was represented by just a single digit.
119 if (isSeparatorChar(*p)) {
123 throw invalid_argument(to<string>("invalid MAC address \"", str,
124 "\": contains non-hex digit"));
130 // Update parsed with the newly parsed byte
131 parsed[byteIndex] = ((upper << 4) | lower);
134 if (p != str.end()) {
135 // String is too long to be a MAC address
136 throw invalid_argument(to<string>("invalid MAC address \"", str,
137 "\": found trailing characters"));
140 // Only update now that we have successfully parsed the entire
141 // string. This way we remain unchanged on error.
142 setFromBinary(ByteRange(parsed, SIZE));
145 void MacAddress::setFromBinary(ByteRange value) {
146 if (value.size() != SIZE) {
147 throw invalid_argument(to<string>("MAC address must be 6 bytes "
148 "long, got ", value.size()));
150 memcpy(bytes_ + 2, value.begin(), SIZE);
153 std::ostream& operator<<(std::ostream& os, MacAddress address) {
154 os << address.toString();