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 #include "pw_bluetooth_sapphire/internal/host/common/device_address.h"
16
17 #include <pw_assert/check.h>
18
19 #include "pw_bluetooth/hci_common.emb.h"
20 #include "pw_preprocessor/compiler.h"
21 #include "pw_string/format.h"
22
23 namespace bt {
24 namespace {
25
TypeToString(DeviceAddress::Type type)26 std::string TypeToString(DeviceAddress::Type type) {
27 switch (type) {
28 case DeviceAddress::Type::kBREDR:
29 return "(BD_ADDR) ";
30 case DeviceAddress::Type::kLEPublic:
31 return "(LE publ) ";
32 case DeviceAddress::Type::kLERandom:
33 return "(LE rand) ";
34 case DeviceAddress::Type::kLEAnonymous:
35 return "(LE anon) ";
36 }
37
38 return "(invalid) ";
39 }
40
41 } // namespace
42
DeviceAddressBytes()43 DeviceAddressBytes::DeviceAddressBytes() { SetToZero(); }
44
DeviceAddressBytes(std::array<uint8_t,kDeviceAddressSize> bytes)45 DeviceAddressBytes::DeviceAddressBytes(
46 std::array<uint8_t, kDeviceAddressSize> bytes) {
47 bytes_ = bytes;
48 }
49
DeviceAddressBytes(const ByteBuffer & bytes)50 DeviceAddressBytes::DeviceAddressBytes(const ByteBuffer& bytes) {
51 PW_DCHECK(bytes.size() == bytes_.size());
52 std::copy(bytes.cbegin(), bytes.cend(), bytes_.begin());
53 }
54
DeviceAddressBytes(pw::bluetooth::emboss::BdAddrView view)55 DeviceAddressBytes::DeviceAddressBytes(pw::bluetooth::emboss::BdAddrView view) {
56 pw::bluetooth::emboss::MakeBdAddrView(&bytes_).CopyFrom(view);
57 }
58
ToString() const59 std::string DeviceAddressBytes::ToString() const {
60 constexpr size_t out_size = sizeof("00:00:00:00:00:00");
61 char out[out_size] = "";
62 // Ignore errors. If an error occurs, an empty string will be returned.
63 pw::StatusWithSize result =
64 pw::string::Format({out, sizeof(out)},
65 "%02X:%02X:%02X:%02X:%02X:%02X",
66 bytes_[5],
67 bytes_[4],
68 bytes_[3],
69 bytes_[2],
70 bytes_[1],
71 bytes_[0]);
72 PW_DCHECK(result.ok());
73 return out;
74 }
75
SetToZero()76 void DeviceAddressBytes::SetToZero() { bytes_.fill(0); }
77
Hash() const78 std::size_t DeviceAddressBytes::Hash() const {
79 uint64_t bytes_as_int = 0;
80 int shift_amount = 0;
81 for (const uint8_t& byte : bytes_) {
82 bytes_as_int |= (static_cast<uint64_t>(byte) << shift_amount);
83 shift_amount += 8;
84 }
85
86 std::hash<uint64_t> hash_func;
87 return hash_func(bytes_as_int);
88 }
89
DeviceAddress()90 DeviceAddress::DeviceAddress() : type_(Type::kBREDR) {}
91
DeviceAddress(Type type,const DeviceAddressBytes & value)92 DeviceAddress::DeviceAddress(Type type, const DeviceAddressBytes& value)
93 : type_(type), value_(value) {}
94
DeviceAddress(Type type,std::array<uint8_t,kDeviceAddressSize> bytes)95 DeviceAddress::DeviceAddress(Type type,
96 std::array<uint8_t, kDeviceAddressSize> bytes)
97 : DeviceAddress(type, DeviceAddressBytes(bytes)) {}
98
DeviceAddrToLeAddr(DeviceAddress::Type type)99 pw::bluetooth::emboss::LEAddressType DeviceAddress::DeviceAddrToLeAddr(
100 DeviceAddress::Type type) {
101 PW_MODIFY_DIAGNOSTICS_PUSH();
102 PW_MODIFY_DIAGNOSTIC(ignored, "-Wswitch-enum");
103 switch (type) {
104 case DeviceAddress::Type::kLEPublic: {
105 return pw::bluetooth::emboss::LEAddressType::PUBLIC;
106 }
107 case DeviceAddress::Type::kLERandom: {
108 return pw::bluetooth::emboss::LEAddressType::RANDOM;
109 }
110 default: {
111 PW_CRASH("invalid DeviceAddressType");
112 }
113 }
114 PW_MODIFY_DIAGNOSTICS_POP();
115 }
116
DeviceAddrToLePeerAddr(Type type)117 pw::bluetooth::emboss::LEPeerAddressType DeviceAddress::DeviceAddrToLePeerAddr(
118 Type type) {
119 switch (type) {
120 case DeviceAddress::Type::kBREDR: {
121 PW_CRASH("BR/EDR address not convertible to LE address");
122 }
123 case DeviceAddress::Type::kLEPublic: {
124 return pw::bluetooth::emboss::LEPeerAddressType::PUBLIC;
125 }
126 case DeviceAddress::Type::kLERandom: {
127 return pw::bluetooth::emboss::LEPeerAddressType::RANDOM;
128 }
129 case DeviceAddress::Type::kLEAnonymous: {
130 return pw::bluetooth::emboss::LEPeerAddressType::ANONYMOUS;
131 }
132 default: {
133 PW_CRASH("invalid DeviceAddressType");
134 }
135 }
136 }
137
138 pw::bluetooth::emboss::LEPeerAddressTypeNoAnon
DeviceAddrToLePeerAddrNoAnon(Type type)139 DeviceAddress::DeviceAddrToLePeerAddrNoAnon(Type type) {
140 switch (type) {
141 case DeviceAddress::Type::kBREDR: {
142 PW_CRASH("BR/EDR address not convertible to LE address");
143 }
144 case DeviceAddress::Type::kLEPublic: {
145 return pw::bluetooth::emboss::LEPeerAddressTypeNoAnon::PUBLIC;
146 }
147 case DeviceAddress::Type::kLERandom: {
148 return pw::bluetooth::emboss::LEPeerAddressTypeNoAnon::RANDOM;
149 }
150 case DeviceAddress::Type::kLEAnonymous: {
151 PW_CRASH("invalid DeviceAddressType; anonymous type unsupported");
152 }
153 default: {
154 PW_CRASH("invalid DeviceAddressType");
155 }
156 }
157 }
158
159 pw::bluetooth::emboss::LEExtendedAddressType
DeviceAddrToLeExtendedAddr(Type type)160 DeviceAddress::DeviceAddrToLeExtendedAddr(Type type) {
161 switch (type) {
162 case DeviceAddress::Type::kBREDR: {
163 PW_CRASH("BR/EDR address not convertible to LE address");
164 }
165 case DeviceAddress::Type::kLEPublic: {
166 return pw::bluetooth::emboss::LEExtendedAddressType::PUBLIC;
167 }
168 case DeviceAddress::Type::kLERandom: {
169 return pw::bluetooth::emboss::LEExtendedAddressType::RANDOM;
170 }
171 case DeviceAddress::Type::kLEAnonymous: {
172 return pw::bluetooth::emboss::LEExtendedAddressType::ANONYMOUS;
173 }
174 }
175 }
176
DeviceAddrToLeOwnAddr(Type type)177 pw::bluetooth::emboss::LEOwnAddressType DeviceAddress::DeviceAddrToLeOwnAddr(
178 Type type) {
179 switch (type) {
180 case DeviceAddress::Type::kLERandom: {
181 return pw::bluetooth::emboss::LEOwnAddressType::RANDOM;
182 }
183 case DeviceAddress::Type::kLEPublic: {
184 return pw::bluetooth::emboss::LEOwnAddressType::PUBLIC;
185 }
186 case DeviceAddress::Type::kLEAnonymous:
187 case DeviceAddress::Type::kBREDR:
188 default: {
189 PW_CRASH("invalid DeviceAddressType");
190 }
191 }
192 }
193
LeAddrToDeviceAddr(pw::bluetooth::emboss::LEAddressType type)194 DeviceAddress::Type DeviceAddress::LeAddrToDeviceAddr(
195 pw::bluetooth::emboss::LEAddressType type) {
196 switch (type) {
197 case pw::bluetooth::emboss::LEAddressType::PUBLIC:
198 case pw::bluetooth::emboss::LEAddressType::PUBLIC_IDENTITY: {
199 return DeviceAddress::Type::kLEPublic;
200 }
201 case pw::bluetooth::emboss::LEAddressType::RANDOM:
202 case pw::bluetooth::emboss::LEAddressType::RANDOM_IDENTITY: {
203 return DeviceAddress::Type::kLERandom;
204 }
205 default: {
206 PW_CRASH("invalid LEAddressType");
207 }
208 }
209 }
210
LeAddrToDeviceAddr(pw::bluetooth::emboss::LEPeerAddressType type)211 DeviceAddress::Type DeviceAddress::LeAddrToDeviceAddr(
212 pw::bluetooth::emboss::LEPeerAddressType type) {
213 switch (type) {
214 case pw::bluetooth::emboss::LEPeerAddressType::PUBLIC: {
215 return DeviceAddress::Type::kLEPublic;
216 }
217 case pw::bluetooth::emboss::LEPeerAddressType::RANDOM: {
218 return DeviceAddress::Type::kLERandom;
219 }
220 case pw::bluetooth::emboss::LEPeerAddressType::ANONYMOUS: {
221 return DeviceAddress::Type::kLEAnonymous;
222 }
223 default: {
224 PW_CRASH("invalid LEPeerAddressType");
225 }
226 }
227 }
228
LeAddrToDeviceAddr(pw::bluetooth::emboss::LEPeerAddressTypeNoAnon type)229 DeviceAddress::Type DeviceAddress::LeAddrToDeviceAddr(
230 pw::bluetooth::emboss::LEPeerAddressTypeNoAnon type) {
231 switch (type) {
232 case pw::bluetooth::emboss::LEPeerAddressTypeNoAnon::PUBLIC: {
233 return DeviceAddress::Type::kLEPublic;
234 }
235 case pw::bluetooth::emboss::LEPeerAddressTypeNoAnon::RANDOM: {
236 return DeviceAddress::Type::kLERandom;
237 }
238 default: {
239 PW_CRASH("invalid LEPeerAddressTypeNoAnon");
240 }
241 }
242 }
243
LeAddrToDeviceAddr(pw::bluetooth::emboss::LEExtendedAddressType type)244 std::optional<DeviceAddress::Type> DeviceAddress::LeAddrToDeviceAddr(
245 pw::bluetooth::emboss::LEExtendedAddressType type) {
246 switch (type) {
247 case pw::bluetooth::emboss::LEExtendedAddressType::PUBLIC:
248 case pw::bluetooth::emboss::LEExtendedAddressType::PUBLIC_IDENTITY: {
249 return DeviceAddress::Type::kLEPublic;
250 }
251 case pw::bluetooth::emboss::LEExtendedAddressType::RANDOM:
252 case pw::bluetooth::emboss::LEExtendedAddressType::RANDOM_IDENTITY: {
253 return DeviceAddress::Type::kLERandom;
254 }
255 case pw::bluetooth::emboss::LEExtendedAddressType::ANONYMOUS: {
256 return DeviceAddress::Type::kLEAnonymous;
257 }
258 default: {
259 return std::nullopt;
260 }
261 }
262 }
263
IsResolvablePrivate() const264 bool DeviceAddress::IsResolvablePrivate() const {
265 // "The two most significant bits of [a RPA] shall be equal to 0 and 1".
266 // (Vol 6, Part B, 1.3.2.2).
267 uint8_t msb = value_.bytes()[5];
268 return type_ == Type::kLERandom && (msb & 0b01000000) && (~msb & 0b10000000);
269 }
270
IsNonResolvablePrivate() const271 bool DeviceAddress::IsNonResolvablePrivate() const {
272 // "The two most significant bits of [a NRPA] shall be equal to 0".
273 // (Vol 6, Part B, 1.3.2.2).
274 uint8_t msb = value_.bytes()[5];
275 return type_ == Type::kLERandom && !(msb & 0b11000000);
276 }
277
IsStaticRandom() const278 bool DeviceAddress::IsStaticRandom() const {
279 // "The two most significant bits of [a static random address] shall be
280 // equal to 1". (Vol 6, Part B, 1.3.2.1).
281 uint8_t msb = value_.bytes()[5];
282 return type_ == Type::kLERandom && ((msb & 0b11000000) == 0b11000000);
283 }
284
Hash() const285 std::size_t DeviceAddress::Hash() const {
286 const Type type_for_hashing = IsPublic() ? Type::kBREDR : type_;
287 std::size_t const h1(std::hash<Type>{}(type_for_hashing));
288 std::size_t h2 = value_.Hash();
289
290 return h1 ^ (h2 << 1);
291 }
292
ToString() const293 std::string DeviceAddress::ToString() const {
294 return TypeToString(type_) + value_.ToString();
295 }
296
297 } // namespace bt
298
299 namespace std {
300
operator ()(argument_type const & value) const301 hash<bt::DeviceAddress>::result_type hash<bt::DeviceAddress>::operator()(
302 argument_type const& value) const {
303 return value.Hash();
304 }
305
306 } // namespace std
307