• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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::LEExtendedAddressType
110   DeviceAddrToLeExtendedAddr(Type type);
111   static pw::bluetooth::emboss::LEOwnAddressType DeviceAddrToLeOwnAddr(
112       Type type);
113 
114   static Type LeAddrToDeviceAddr(pw::bluetooth::emboss::LEAddressType type);
115   static Type LeAddrToDeviceAddr(pw::bluetooth::emboss::LEPeerAddressType type);
116   static Type LeAddrToDeviceAddr(
117       pw::bluetooth::emboss::LEPeerAddressTypeNoAnon type);
118   static std::optional<Type> LeAddrToDeviceAddr(
119       pw::bluetooth::emboss::LEExtendedAddressType type);
120 
121   // The default constructor initializes the address to 00:00:00:00:00:00 and
122   // the type to Type::kBREDR.
123   DeviceAddress();
124 
125   // Initializes the contents from raw data.
126   DeviceAddress(Type type, const DeviceAddressBytes& value);
127   DeviceAddress(Type type, std::array<uint8_t, kDeviceAddressSize> bytes);
128 
type()129   Type type() const { return type_; }
value()130   const DeviceAddressBytes& value() const { return value_; }
131 
IsBrEdr()132   bool IsBrEdr() const { return type_ == Type::kBREDR; }
IsLowEnergy()133   bool IsLowEnergy() const {
134     return type_ == Type::kLEPublic || type_ == Type::kLERandom ||
135            type_ == Type::kLEAnonymous;
136   }
137 
138   // Comparison operators. The equality and less-than operators are needed to
139   // support unordered and ordered containers, respectively.
140   bool operator==(const DeviceAddress& other) const {
141     return IsTypeCompatible(other) && value_ == other.value_;
142   }
143   bool operator!=(const DeviceAddress& other) const {
144     return !(*this == other);
145   }
146   bool operator<(const DeviceAddress& other) const {
147     // Treat |type_| as the higher-order bits
148     if (type_ < other.type_ && !IsTypeCompatible(other)) {
149       return true;
150     }
151     return IsTypeCompatible(other) && value_ < other.value_;
152   }
153 
154   // Returns true if this address is a BR/EDR BD_ADDR or LE public address.
IsPublic()155   bool IsPublic() const {
156     return type_ == Type::kBREDR || type_ == Type::kLEPublic;
157   }
158 
159   // Returns true if this address is a Resolvable Private Address.
160   bool IsResolvablePrivate() const;
161 
162   // Returns true if this address is a Non-resolvable Private Address.
163   bool IsNonResolvablePrivate() const;
164 
165   // Returns true if this is a static random device address.
166   bool IsStaticRandom() const;
167 
168   // Returns a hash of the contents of this address.
169   std::size_t Hash() const;
170 
171   // Returns a string representation of this address.
172   std::string ToString() const;
173 
174  private:
175   // True if both addresses have types indicating they're used for the same
176   // purpose
IsTypeCompatible(const DeviceAddress & other)177   bool IsTypeCompatible(const DeviceAddress& other) const {
178     return (type_ == other.type_) || (IsPublic() && other.IsPublic());
179   }
180 
181   Type type_;
182   DeviceAddressBytes value_;
183 };
184 
185 static_assert(sizeof(DeviceAddress) == 8,
186               "DeviceAddress must take up exactly 8 bytes");
187 
188 }  // namespace bt
189 
190 // Custom specialization of std::hash to support unordered associative
191 // containers.
192 namespace std {
193 
194 template <>
195 struct hash<bt::DeviceAddress> {
196   using argument_type = bt::DeviceAddress;
197   using result_type = std::size_t;
198 
199   result_type operator()(argument_type const& value) const;
200 };
201 
202 }  // namespace std
203