1 // Copyright 2023 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 #pragma once
16 #include <pw_bluetooth/hci_common.emb.h>
17 
18 #include <array>
19 #include <initializer_list>
20 #include <optional>
21 #include <string>
22 
23 #include "pw_bluetooth_sapphire/internal/host/common/byte_buffer.h"
24 
25 namespace bt {
26 
27 const size_t kDeviceAddressSize = 6;
28 
29 // Represents a 48-bit BD_ADDR. This data structure can be directly serialized
30 // into HCI command payloads.
31 class DeviceAddressBytes {
32  public:
33   // The default constructor initializes the address to 00:00:00:00:00:00.
34   DeviceAddressBytes();
35 
36   // Initializes the contents from |bytes|.
37   explicit DeviceAddressBytes(std::array<uint8_t, kDeviceAddressSize> bytes);
38   explicit DeviceAddressBytes(const ByteBuffer& bytes);
39   explicit DeviceAddressBytes(pw::bluetooth::emboss::BdAddrView view);
40 
41   // Returns a string representation of the device address. The bytes in
42   // human-readable form will appear in big-endian byte order even though the
43   // underlying array stores the bytes in little-endian. The returned string
44   // will be of the form:
45   //
46   //   XX:XX:XX:XX:XX:XX
47   std::string ToString() const;
48 
49   // Sets all bits of the BD_ADDR to 0.
50   void SetToZero();
51 
52   // Returns a view over the raw bytes of this address.
bytes()53   BufferView bytes() const { return BufferView(bytes_.data(), bytes_.size()); }
54 
55   // Comparison operators.
56   bool operator==(const DeviceAddressBytes& other) const {
57     return bytes_ == other.bytes_;
58   }
59   bool operator!=(const DeviceAddressBytes& other) const {
60     return !(*this == other);
61   }
62   bool operator<(const DeviceAddressBytes& other) const {
63     return bytes_ < other.bytes_;
64   }
65 
view()66   pw::bluetooth::emboss::BdAddrView view() const {
67     return pw::bluetooth::emboss::MakeBdAddrView(&bytes_);
68   }
69 
70   // Returns a hash of the contents of this address.
71   std::size_t Hash() const;
72 
73  private:
74   // The raw bytes of the BD_ADDR stored in little-endian byte order.
75   std::array<uint8_t, kDeviceAddressSize> bytes_;
76 };
77 
78 static_assert(sizeof(DeviceAddressBytes) == 6,
79               "DeviceAddressBytes must take up exactly 6 bytes");
80 
81 // DeviceAddress represents a Bluetooth device address, encapsulating the 48-bit
82 // device address and the address type. A DeviceAddress is comparable and can be
83 // used as a key in ordered and unordered associative STL containers.
84 //
85 // TODO(fxbug.dev/42102158): Using the underlying DeviceAddressBytes for
86 // equality, comparison, and hashing effectively obsoletes DeviceAddressBytes as
87 // a separate class. Removing the |type_| field (see bug for rationale) will
88 // make this class compatible with serialization.
89 class DeviceAddress {
90  public:
91   // Bluetooth device address types.
92   enum class Type : uint16_t {
93     // BD_ADDR as used in Bluetooth Classic.
94     kBREDR,
95 
96     // Low Energy Address types.
97     kLEPublic,
98     kLERandom,
99     kLEAnonymous,
100   };
101 
102   // Utilities to convert between DeviceAddress::Type and the LE peer address
103   // type.
104   static pw::bluetooth::emboss::LEAddressType DeviceAddrToLeAddr(Type type);
105   static pw::bluetooth::emboss::LEPeerAddressType DeviceAddrToLePeerAddr(
106       Type type);
107   static pw::bluetooth::emboss::LEPeerAddressTypeNoAnon
108   DeviceAddrToLePeerAddrNoAnon(Type type);
109   static pw::bluetooth::emboss::LEOwnAddressType DeviceAddrToLEOwnAddr(
110       Type type);
111 
112   static Type LeAddrToDeviceAddr(pw::bluetooth::emboss::LEAddressType type);
113   static Type LeAddrToDeviceAddr(pw::bluetooth::emboss::LEPeerAddressType type);
114   static Type LeAddrToDeviceAddr(
115       pw::bluetooth::emboss::LEPeerAddressTypeNoAnon type);
116   static std::optional<Type> LeAddrToDeviceAddr(
117       pw::bluetooth::emboss::LEExtendedAddressType type);
118 
119   // The default constructor initializes the address to 00:00:00:00:00:00 and
120   // the type to Type::kBREDR.
121   DeviceAddress();
122 
123   // Initializes the contents from raw data.
124   DeviceAddress(Type type, const DeviceAddressBytes& value);
125   DeviceAddress(Type type, std::array<uint8_t, kDeviceAddressSize> bytes);
126 
type()127   Type type() const { return type_; }
value()128   const DeviceAddressBytes& value() const { return value_; }
129 
IsBrEdr()130   bool IsBrEdr() const { return type_ == Type::kBREDR; }
IsLowEnergy()131   bool IsLowEnergy() const {
132     return type_ == Type::kLEPublic || type_ == Type::kLERandom ||
133            type_ == Type::kLEAnonymous;
134   }
135 
136   // Comparison operators. The equality and less-than operators are needed to
137   // support unordered and ordered containers, respectively.
138   bool operator==(const DeviceAddress& other) const {
139     return IsTypeCompatible(other) && value_ == other.value_;
140   }
141   bool operator!=(const DeviceAddress& other) const {
142     return !(*this == other);
143   }
144   bool operator<(const DeviceAddress& other) const {
145     // Treat |type_| as the higher-order bits
146     if (type_ < other.type_ && !IsTypeCompatible(other)) {
147       return true;
148     }
149     return IsTypeCompatible(other) && value_ < other.value_;
150   }
151 
152   // Returns true if this address is a BR/EDR BD_ADDR or LE public address.
IsPublic()153   bool IsPublic() const {
154     return type_ == Type::kBREDR || type_ == Type::kLEPublic;
155   }
156 
157   // Returns true if this address is a Resolvable Private Address.
158   bool IsResolvablePrivate() const;
159 
160   // Returns true if this address is a Non-resolvable Private Address.
161   bool IsNonResolvablePrivate() const;
162 
163   // Returns true if this is a static random device address.
164   bool IsStaticRandom() const;
165 
166   // Returns a hash of the contents of this address.
167   std::size_t Hash() const;
168 
169   // Returns a string representation of this address.
170   std::string ToString() const;
171 
172  private:
173   // True if both addresses have types indicating they're used for the same
174   // purpose
IsTypeCompatible(const DeviceAddress & other)175   bool IsTypeCompatible(const DeviceAddress& other) const {
176     return (type_ == other.type_) || (IsPublic() && other.IsPublic());
177   }
178 
179   Type type_;
180   DeviceAddressBytes value_;
181 };
182 
183 static_assert(sizeof(DeviceAddress) == 8,
184               "DeviceAddress must take up exactly 8 bytes");
185 
186 }  // namespace bt
187 
188 // Custom specialization of std::hash to support unordered associative
189 // containers.
190 namespace std {
191 
192 template <>
193 struct hash<bt::DeviceAddress> {
194   using argument_type = bt::DeviceAddress;
195   using result_type = std::size_t;
196 
197   result_type operator()(argument_type const& value) const;
198 };
199 
200 }  // namespace std
201