1 /* 2 * Copyright 2022 The Android Open Source Project 3 * 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 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 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. 15 */ 16 17 #pragma once 18 19 #include <fmt/core.h> 20 #include <packet_runtime.h> 21 22 #include <array> 23 #include <cstdint> 24 #include <cstring> 25 #include <functional> 26 #include <initializer_list> 27 #include <optional> 28 #include <ostream> 29 #include <string> 30 #include <vector> 31 32 namespace bluetooth::hci { 33 34 class Address final : public pdl::packet::Builder { 35 public: 36 static constexpr size_t kLength = 6; 37 38 // Bluetooth MAC address bytes saved in little endian format. 39 // The address MSB is address[5], the address LSB is address[0]. 40 // Note that the textual representation follows the big endian format, 41 // ie. Address{0, 1, 2, 3, 4, 5} is represented as 05:04:03:02:01:00. 42 std::array<uint8_t, kLength> address = {}; 43 44 constexpr Address() = default; 45 constexpr Address(std::array<uint8_t, kLength> const& address); 46 Address(const uint8_t (&address)[kLength]); 47 Address(std::initializer_list<uint8_t> l); 48 49 // storage::Serializable methods 50 std::string ToString() const; 51 static std::optional<Address> FromString(const std::string& from); 52 53 bool operator<(const Address& rhs) const { return address < rhs.address; } 54 bool operator==(const Address& rhs) const { return address == rhs.address; } 55 bool operator>(const Address& rhs) const { return (rhs < *this); } 56 bool operator<=(const Address& rhs) const { return !(*this > rhs); } 57 bool operator>=(const Address& rhs) const { return !(*this < rhs); } 58 bool operator!=(const Address& rhs) const { return !(*this == rhs); } 59 IsEmpty()60 bool IsEmpty() const { return *this == kEmpty; } data()61 uint8_t* data() { return address.data(); } data()62 uint8_t const* data() const { return address.data(); } 63 64 // Packet parser interface. 65 static bool Parse(pdl::packet::slice& input, Address* output); 66 67 // Packet builder interface. GetSize()68 size_t GetSize() const override { return kLength; } Serialize(std::vector<uint8_t> & output)69 void Serialize(std::vector<uint8_t>& output) const override { 70 output.insert(output.end(), address.begin(), address.end()); 71 } 72 73 // Converts |string| to Address and places it in |to|. If |from| does 74 // not represent a Bluetooth address, |to| is not modified and this function 75 // returns false. Otherwise, it returns true. 76 static bool FromString(const std::string& from, Address& to); 77 78 // Copies |from| raw Bluetooth address octets to the local object. 79 // Returns the number of copied octets - should be always Address::kLength 80 size_t FromOctets(const uint8_t* from); 81 82 static bool IsValidAddress(const std::string& address); 83 84 static const Address kEmpty; // 00:00:00:00:00:00 85 static const Address kAny; // FF:FF:FF:FF:FF:FF 86 }; 87 88 inline std::ostream& operator<<(std::ostream& os, const Address& a) { 89 os << a.ToString(); 90 return os; 91 } 92 93 } // namespace bluetooth::hci 94 95 namespace std { 96 template <> 97 struct hash<bluetooth::hci::Address> { 98 std::size_t operator()(const bluetooth::hci::Address& address) const { 99 uint64_t address_int = 0; 100 for (auto b : address.address) { 101 address_int <<= 8; 102 address_int |= b; 103 } 104 return std::hash<uint64_t>{}(address_int); 105 } 106 }; 107 } // namespace std 108 109 template <> 110 struct fmt::formatter<bluetooth::hci::Address> { 111 // Presentation format: 'x' - lowercase, 'X' - uppercase. 112 char presentation = 'x'; 113 114 // Parses format specifications of the form ['x' | 'X']. 115 constexpr auto parse(format_parse_context& ctx) 116 -> format_parse_context::iterator { 117 // Parse the presentation format and store it in the formatter: 118 auto it = ctx.begin(); 119 auto end = ctx.end(); 120 if (it != end && (*it == 'x' || *it == 'X')) { 121 presentation = *it++; 122 } 123 124 // Check if reached the end of the range: 125 if (it != end && *it != '}') { 126 throw_format_error("invalid format"); 127 } 128 129 // Return an iterator past the end of the parsed range: 130 return it; 131 } 132 133 // Formats the address a using the parsed format specification (presentation) 134 // stored in this formatter. 135 auto format(const bluetooth::hci::Address& a, format_context& ctx) const 136 -> format_context::iterator { 137 return presentation == 'x' 138 ? fmt::format_to(ctx.out(), 139 "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}", 140 a.address[5], a.address[4], a.address[3], 141 a.address[2], a.address[1], a.address[0]) 142 : fmt::format_to(ctx.out(), 143 "{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}", 144 a.address[5], a.address[4], a.address[3], 145 a.address[2], a.address[1], a.address[0]); 146 } 147 }; 148