xref: /aosp_15_r20/external/pigweed/pw_bluetooth_sapphire/public/pw_bluetooth_sapphire/internal/host/gap/peer.h (revision 61c4878ac05f98d0ceed94b57d316916de578985)
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 <lib/fit/defer.h>
17 
18 #include <string>
19 #include <unordered_set>
20 
21 #include "pw_bluetooth_sapphire/internal/host/common/advertising_data.h"
22 #include "pw_bluetooth_sapphire/internal/host/common/byte_buffer.h"
23 #include "pw_bluetooth_sapphire/internal/host/common/device_address.h"
24 #include "pw_bluetooth_sapphire/internal/host/common/inspectable.h"
25 #include "pw_bluetooth_sapphire/internal/host/common/macros.h"
26 #include "pw_bluetooth_sapphire/internal/host/common/uuid.h"
27 #include "pw_bluetooth_sapphire/internal/host/gap/gap.h"
28 #include "pw_bluetooth_sapphire/internal/host/gap/peer_metrics.h"
29 #include "pw_bluetooth_sapphire/internal/host/gatt/persisted_data.h"
30 #include "pw_bluetooth_sapphire/internal/host/hci-spec/constants.h"
31 #include "pw_bluetooth_sapphire/internal/host/hci-spec/le_connection_parameters.h"
32 #include "pw_bluetooth_sapphire/internal/host/hci-spec/lmp_feature_set.h"
33 #include "pw_bluetooth_sapphire/internal/host/hci/connection.h"
34 #include "pw_bluetooth_sapphire/internal/host/sm/types.h"
35 
36 namespace bt::gap {
37 
38 class PeerCache;
39 
40 // Represents a remote Bluetooth device that is known to the current system due
41 // to discovery and/or connection and bonding procedures. These devices can be
42 // LE-only, Classic-only, or dual-mode.
43 //
44 // Instances should not be created directly and must be obtained via a
45 // PeerCache.
46 class Peer final {
47  public:
48   using PeerCallback = fit::function<void(const Peer&)>;
49 
50   // Describes the change(s) that caused the peer to notify listeners.
51   enum class NotifyListenersChange {
52     kBondNotUpdated,  // No persistent data has changed
53     kBondUpdated,     // Persistent data has changed
54   };
55   using NotifyListenersCallback =
56       fit::function<void(const Peer&, NotifyListenersChange)>;
57 
58   using StoreLowEnergyBondCallback =
59       fit::function<bool(const sm::PairingData&)>;
60 
61   // Caller must ensure that callbacks are non-empty.
62   // Note that the ctor is only intended for use by PeerCache.
63   // Expanding access would a) violate the constraint that all Peers
64   // are created through a PeerCache, and b) introduce lifetime issues
65   // (do the callbacks outlive |this|?).
66   Peer(NotifyListenersCallback notify_listeners_callback,
67        PeerCallback update_expiry_callback,
68        PeerCallback dual_mode_callback,
69        StoreLowEnergyBondCallback store_le_bond_callback,
70        PeerId identifier,
71        const DeviceAddress& address,
72        bool connectable,
73        PeerMetrics* peer_metrics,
74        pw::async::Dispatcher& dispatcher);
75 
IsSecureSimplePairingSupported()76   bool IsSecureSimplePairingSupported() {
77     return lmp_features_->HasBit(
78                /*page=*/0,
79                hci_spec::LMPFeature::kSecureSimplePairingControllerSupport) &&
80            lmp_features_->HasBit(
81                /*page=*/1,
82                hci_spec::LMPFeature::kSecureSimplePairingHostSupport);
83   }
84 
85   // Connection state as considered by the GAP layer. This may not correspond
86   // exactly with the presence or absence of a link at the link layer. For
87   // example, GAP may consider a peer disconnected whilst the link disconnection
88   // procedure is still continuing.
89   enum class ConnectionState {
90     // No link exists between the local adapter and peer or link is being torn
91     // down (disconnection command has been sent).
92     kNotConnected,
93 
94     // Currently establishing a link, performing service discovery, or
95     // setting up encryption. In this state, a link may have been
96     // established but it is not ready to use yet.
97     kInitializing,
98 
99     // Link setup, service discovery, and any encryption setup has completed
100     kConnected
101   };
102   static std::string ConnectionStateToString(Peer::ConnectionState);
103 
104   // Description of auto-connect behaviors.
105   //
106   // By default, the stack will auto-connect to any bonded devices as soon as
107   // soon as they become available.
108   enum class AutoConnectBehavior {
109     // Always auto-connect device when possible.
110     kAlways,
111 
112     // Ignore auto-connection possibilities, but reset to kAlways after the next
113     // manual connection.
114     kSkipUntilNextConnection,
115   };
116 
117   // This device's name can be read from various sources: LE advertisements,
118   // Inquiry results, Name Discovery Procedure, the GAP service, or from a
119   // restored bond. When a name is read, it should be registered along with its
120   // source location. `RegisterName()` will update the device name attribute if
121   // the newly encountered name's source is of higher priority (lower enum
122   // value) than that of the existing name.
123   enum class NameSource {
124     kGenericAccessService = /*highest priority*/ 0,
125     kNameDiscoveryProcedure = 1,
126     kInquiryResultComplete = 2,
127     kAdvertisingDataComplete = 3,
128     kInquiryResultShortened = 4,
129     kAdvertisingDataShortened = 5,
130     kUnknown = /*lowest priority*/ 6,
131   };
132   static std::string NameSourceToString(Peer::NameSource);
133 
134   static constexpr const char* kInspectPeerIdName = "peer_id";
135   static constexpr const char* kInspectPeerNameName = "name";
136   static constexpr const char* kInspectTechnologyName = "technology";
137   static constexpr const char* kInspectAddressName = "address";
138   static constexpr const char* kInspectConnectableName = "connectable";
139   static constexpr const char* kInspectTemporaryName = "temporary";
140   static constexpr const char* kInspectFeaturesName = "features";
141   static constexpr const char* kInspectVersionName = "hci_version";
142   static constexpr const char* kInspectManufacturerName = "manufacturer";
143 
144   // Attach peer as child node of |parent| with specified |name|.
145   void AttachInspect(inspect::Node& parent, std::string name = "peer");
146 
147   enum class TokenType { kInitializing, kConnection };
148   template <TokenType T>
149   class TokenWithCallback {
150    public:
TokenWithCallback(fit::callback<void ()> on_destruction)151     explicit TokenWithCallback(fit::callback<void()> on_destruction)
152         : on_destruction_(std::move(on_destruction)) {}
153     ~TokenWithCallback() = default;
154     TokenWithCallback(TokenWithCallback&&) noexcept = default;
155     TokenWithCallback& operator=(TokenWithCallback&&) noexcept = default;
156 
157    private:
158     fit::deferred_callback on_destruction_;
159     BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(TokenWithCallback);
160   };
161 
162   // InitializingConnectionToken is meant to be held by a connection request
163   // object. When the request object is destroyed, the specified callback will
164   // be called to update the connection state.
165   using InitializingConnectionToken =
166       TokenWithCallback<TokenType::kInitializing>;
167 
168   // ConnectionToken is meant to be held by a connection object. When the
169   // connection object is destroyed, the specified callback will be called to
170   // update the connection state.
171   using ConnectionToken = TokenWithCallback<TokenType::kConnection>;
172 
173   // Contains Peer data that apply only to the LE transport.
174   class LowEnergyData final {
175    public:
176     static constexpr const char* kInspectNodeName = "le_data";
177     static constexpr const char* kInspectConnectionStateName =
178         "connection_state";
179     static constexpr const char* kInspectAdvertisingDataParseFailureCountName =
180         "adv_data_parse_failure_count";
181     static constexpr const char* kInspectLastAdvertisingDataParseFailureName =
182         "last_adv_data_parse_failure";
183     static constexpr const char* kInspectBondDataName = "bonded";
184     static constexpr const char* kInspectFeaturesName = "features";
185 
186     explicit LowEnergyData(Peer* owner);
187 
188     void AttachInspect(inspect::Node& parent,
189                        std::string name = kInspectNodeName);
190 
191     // Current connection state.
connection_state()192     ConnectionState connection_state() const {
193       return connected()      ? ConnectionState::kConnected
194              : initializing() ? ConnectionState::kInitializing
195                               : ConnectionState::kNotConnected;
196     }
connected()197     bool connected() const { return connection_tokens_count_ > 0; }
initializing()198     bool initializing() const {
199       return !connected() && initializing_tokens_count_ > 0;
200     }
201 
bonded()202     bool bonded() const { return bond_data_->has_value(); }
should_auto_connect()203     bool should_auto_connect() const {
204       return bonded() && auto_conn_behavior_ == AutoConnectBehavior::kAlways;
205     }
206 
207     // Note that it is possible for `advertising_data()` to return a non-empty
208     // buffer while this method returns std::nullopt, as AdvertisingData is only
209     // stored if it is parsed correctly.
210     // TODO(fxbug.dev/42166259): Migrate clients off of advertising_data, so
211     // that we do not need to store the raw buffer after parsing it.
212     const std::optional<std::reference_wrapper<const AdvertisingData>>
parsed_advertising_data()213     parsed_advertising_data() const {
214       if (parsed_adv_data_.is_error()) {
215         return std::nullopt;
216       }
217       return std::cref(parsed_adv_data_.value());
218     }
219     // Returns the timestamp associated with the most recently successfully
220     // parsed AdvertisingData.
221     std::optional<pw::chrono::SystemClock::time_point>
parsed_advertising_data_timestamp()222     parsed_advertising_data_timestamp() const {
223       return adv_timestamp_;
224     }
225 
226     // Returns the error, if any, encountered when parsing the advertising data
227     // from the peer.
advertising_data_error()228     std::optional<AdvertisingData::ParseError> advertising_data_error() const {
229       if (!parsed_adv_data_.is_error()) {
230         return std::nullopt;
231       }
232       return parsed_adv_data_.error_value();
233     }
234 
235     // Most recently used LE connection parameters. Has no value if the peer
236     // has never been connected.
237     const std::optional<hci_spec::LEConnectionParameters>&
connection_parameters()238     connection_parameters() const {
239       return conn_params_;
240     }
241 
242     // Preferred LE connection parameters as reported by the peer.
243     const std::optional<hci_spec::LEPreferredConnectionParameters>&
preferred_connection_parameters()244     preferred_connection_parameters() const {
245       return preferred_conn_params_;
246     }
247 
248     // This peer's LE bond data, if bonded.
bond_data()249     const std::optional<sm::PairingData>& bond_data() const {
250       return *bond_data_;
251     }
252 
feature_interrogation_complete()253     bool feature_interrogation_complete() const {
254       return feature_interrogation_complete_;
255     }
256 
257     // Bit mask of LE features (Core Spec v5.2, Vol 6, Part B, Section 4.6).
features()258     std::optional<hci_spec::LESupportedFeatures> features() const {
259       return *features_;
260     }
261 
262     // Setters:
263 
264     // Overwrites the stored advertising and scan response data with the
265     // contents of |data| and updates the known RSSI and timestamp with the
266     // given values.
267     void SetAdvertisingData(int8_t rssi,
268                             const ByteBuffer& data,
269                             pw::chrono::SystemClock::time_point timestamp);
270 
271     // Register a connection that is in the request/initializing state. A token
272     // is returned that should be owned until the initialization is complete or
273     // canceled. The connection state may be updated and listeners may be
274     // notified. Multiple initializating connections may be registered.
275     [[nodiscard]] InitializingConnectionToken RegisterInitializingConnection();
276 
277     // Register a connection that is in the connected state. A token is returned
278     // that should be owned until the connection is disconnected. The connection
279     // state may be updated and listeners may be notified. Multiple connections
280     // may be registered.
281     [[nodiscard]] ConnectionToken RegisterConnection();
282 
283     // Modify the current or preferred connection parameters.
284     // The device must be connectable.
285     void SetConnectionParameters(const hci_spec::LEConnectionParameters& value);
286     void SetPreferredConnectionParameters(
287         const hci_spec::LEPreferredConnectionParameters& value);
288 
289     // Stores the bond in PeerCache, which updates the address map and calls
290     // SetBondData.
291     bool StoreBond(const sm::PairingData& bond_data);
292 
293     // Stores LE bonding data and makes this "bonded."
294     // Marks as non-temporary if necessary.
295     // This should only be called by PeerCache.
296     void SetBondData(const sm::PairingData& bond_data);
297 
298     // Removes any stored keys. Does not make the peer temporary, even if it
299     // is disconnected. Does not notify listeners.
300     void ClearBondData();
301 
SetFeatureInterrogationComplete()302     void SetFeatureInterrogationComplete() {
303       feature_interrogation_complete_ = true;
304     }
305 
SetFeatures(hci_spec::LESupportedFeatures features)306     void SetFeatures(hci_spec::LESupportedFeatures features) {
307       features_.Set(features);
308     }
309 
310     // Get pieces of the GATT database that must be persisted for bonded peers.
get_service_changed_gatt_data()311     const gatt::ServiceChangedCCCPersistedData& get_service_changed_gatt_data()
312         const {
313       return service_changed_gatt_data_;
314     }
315 
316     // Set pieces of the GATT database that must be persisted for bonded peers.
set_service_changed_gatt_data(const gatt::ServiceChangedCCCPersistedData & gatt_data)317     void set_service_changed_gatt_data(
318         const gatt::ServiceChangedCCCPersistedData& gatt_data) {
319       service_changed_gatt_data_ = gatt_data;
320     }
321 
set_auto_connect_behavior(AutoConnectBehavior behavior)322     void set_auto_connect_behavior(AutoConnectBehavior behavior) {
323       auto_conn_behavior_ = behavior;
324     }
325 
set_sleep_clock_accuracy(pw::bluetooth::emboss::LESleepClockAccuracyRange sca)326     void set_sleep_clock_accuracy(
327         pw::bluetooth::emboss::LESleepClockAccuracyRange sca) {
328       sleep_clock_accuracy_ = sca;
329     }
330 
331     std::optional<pw::bluetooth::emboss::LESleepClockAccuracyRange>
sleep_clock_accuracy()332     sleep_clock_accuracy() const {
333       return sleep_clock_accuracy_;
334     }
335 
336     // TODO(armansito): Store most recently seen random address and identity
337     // address separately, once PeerCache can index peers by multiple
338     // addresses.
339 
340    private:
341     struct InspectProperties {
342       inspect::StringProperty connection_state;
343       inspect::StringProperty last_adv_data_parse_failure;
344     };
345 
346     // Called when the connection state changes.
347     void OnConnectionStateMaybeChanged(ConnectionState previous);
348 
349     Peer* peer_;  // weak
350 
351     inspect::Node node_;
352     InspectProperties inspect_properties_;
353 
354     uint16_t initializing_tokens_count_ = 0;
355     uint16_t connection_tokens_count_ = 0;
356     std::optional<hci_spec::LEConnectionParameters> conn_params_;
357     std::optional<hci_spec::LEPreferredConnectionParameters>
358         preferred_conn_params_;
359 
360     // Buffer containing advertising and scan response data appended to each
361     // other. NOTE: Repeated fields in advertising and scan response data are
362     // not deduplicated, so duplicate entries are possible. It is OK to assume
363     // that fields repeated in scan response data supersede those in the
364     // original advertising data when processing fields in order.
365     DynamicByteBuffer adv_data_buffer_;
366     // Time when advertising data was last updated and successfully parsed.
367     std::optional<pw::chrono::SystemClock::time_point> adv_timestamp_;
368     // AdvertisingData parsed from the peer's advertising data, if parsed
369     // correctly.
370     AdvertisingData::ParseResult parsed_adv_data_ =
371         fit::error(AdvertisingData::ParseError::kMissing);
372 
373     BoolInspectable<std::optional<sm::PairingData>> bond_data_;
374 
375     IntInspectable<int64_t> adv_data_parse_failure_count_;
376 
377     AutoConnectBehavior auto_conn_behavior_ = AutoConnectBehavior::kAlways;
378 
379     bool feature_interrogation_complete_ = false;
380 
381     // features_ will be unset if feature interrogation has not been attempted
382     // (in which case feature_interrogation_complete_ will be false) or if
383     // feature interrogation has failed (in which case
384     // feature_interrogation_complete_ will be true).
385     StringInspectable<std::optional<hci_spec::LESupportedFeatures>> features_;
386 
387     // TODO(armansito): Store GATT service UUIDs.
388 
389     // Data persisted from GATT database for bonded peers.
390     gatt::ServiceChangedCCCPersistedData service_changed_gatt_data_;
391 
392     std::optional<pw::bluetooth::emboss::LESleepClockAccuracyRange>
393         sleep_clock_accuracy_;
394   };
395 
396   // Contains Peer data that apply only to the BR/EDR transport.
397   class BrEdrData final {
398    public:
399     static constexpr const char* kInspectNodeName = "bredr_data";
400     static constexpr const char* kInspectConnectionStateName =
401         "connection_state";
402     static constexpr const char* kInspectLinkKeyName = "link_key";
403     static constexpr const char* kInspectServicesName = "services";
404 
405     explicit BrEdrData(Peer* owner);
406 
407     // Attach peer inspect node as a child node of |parent|.
408     void AttachInspect(inspect::Node& parent,
409                        std::string name = kInspectNodeName);
410 
411     // Current connection state.
connection_state()412     ConnectionState connection_state() const {
413       if (connected()) {
414         return ConnectionState::kConnected;
415       }
416       if (initializing()) {
417         return ConnectionState::kInitializing;
418       }
419       return ConnectionState::kNotConnected;
420     }
connected()421     bool connected() const {
422       return !initializing() && connection_tokens_count_ > 0;
423     }
initializing()424     bool initializing() const { return initializing_tokens_count_ > 0; }
425 
bonded()426     bool bonded() const { return link_key_.has_value(); }
427 
428     // Returns the peer's BD_ADDR.
address()429     const DeviceAddress& address() const { return address_; }
430 
431     // Returns the device class reported by the peer, if it is known.
device_class()432     const std::optional<DeviceClass>& device_class() const {
433       return device_class_;
434     }
435 
436     // Returns the page scan repetition mode of the peer, if known.
437     const std::optional<pw::bluetooth::emboss::PageScanRepetitionMode>&
page_scan_repetition_mode()438     page_scan_repetition_mode() const {
439       return page_scan_rep_mode_;
440     }
441 
442     // Returns the clock offset reported by the peer, if known and valid. The
443     // clock offset will NOT have the highest-order bit set and the rest
444     // represents bits 16-2 of CLKNPeripheral-CLK (see
445     // hci_spec::kClockOffsetFlagBit in hci/hci_constants.h).
clock_offset()446     const std::optional<uint16_t>& clock_offset() const {
447       return clock_offset_;
448     }
449 
link_key()450     const std::optional<sm::LTK>& link_key() const { return link_key_; }
451 
services()452     const std::unordered_set<UUID>& services() const { return *services_; }
453 
454     // Setters:
455 
456     // Updates the inquiry data and notifies listeners. These
457     // methods expect HCI inquiry result structures as they are obtained from
458     // the Bluetooth controller. Each field should be encoded in little-endian
459     // byte order.
460     void SetInquiryData(const pw::bluetooth::emboss::InquiryResultView& view);
461     void SetInquiryData(
462         const pw::bluetooth::emboss::InquiryResultWithRssiView& view);
463     void SetInquiryData(
464         const pw::bluetooth::emboss::ExtendedInquiryResultEventView& view);
465 
466     // Sets the data from an incoming connection from this peer.
467     void SetIncomingRequest(
468         const pw::bluetooth::emboss::ConnectionRequestEventView& view);
469 
470     // Register a connection that is in the request/initializing state. A token
471     // is returned that should be owned until the initialization is complete or
472     // canceled. The connection state may be updated and listeners may be
473     // notified. Multiple initializating connections may be registered.
474     [[nodiscard]] InitializingConnectionToken RegisterInitializingConnection();
475 
476     // Register a connection that is in the connected state. A token is returned
477     // that should be owned until the connection is disconnected. The connection
478     // state may be updated and listeners may be notified. Only one connection
479     // may be registered at a time (enforced by assertion).
480     [[nodiscard]] ConnectionToken RegisterConnection();
481 
482     // Stores a link key resulting from Secure Simple Pairing and makes this
483     // peer "bonded." Marks the peer as non-temporary if necessary. All
484     // BR/EDR link keys are "long term" (reusable across sessions).
485     void SetBondData(const sm::LTK& link_key);
486 
487     // Removes any stored link key. Does not make the device temporary, even if
488     // it is disconnected. Does not notify listeners.
489     void ClearBondData();
490 
491     // Adds a service discovered on the peer, identified by |uuid|, then
492     // notifies listeners. No-op if already present.
493     void AddService(UUID uuid);
494 
495     // TODO(armansito): Store BD_ADDR here, once PeerCache can index
496     // devices by multiple addresses.
497 
498    private:
499     struct InspectProperties {
500       inspect::StringProperty connection_state;
501     };
502 
503     // Called when the connection state changes.
504     void OnConnectionStateMaybeChanged(ConnectionState previous);
505 
506     // All multi-byte fields must be in little-endian byte order as they were
507     // received from the controller.
508     void SetInquiryData(
509         DeviceClass device_class,
510         uint16_t clock_offset,
511         pw::bluetooth::emboss::PageScanRepetitionMode page_scan_rep_mode,
512         int8_t rssi = hci_spec::kRSSIInvalid,
513         const BufferView& eir_data = BufferView());
514 
515     // Updates the EIR data field and returns true if any properties changed.
516     bool SetEirData(const ByteBuffer& data);
517 
518     Peer* peer_;  // weak
519     inspect::Node node_;
520     InspectProperties inspect_properties_;
521 
522     uint16_t initializing_tokens_count_ = 0;
523     uint16_t connection_tokens_count_ = 0;
524 
525     DeviceAddress address_;
526     std::optional<DeviceClass> device_class_;
527     std::optional<pw::bluetooth::emboss::PageScanRepetitionMode>
528         page_scan_rep_mode_;
529     std::optional<uint16_t> clock_offset_;
530 
531     std::optional<sm::LTK> link_key_;
532 
533     StringInspectable<std::unordered_set<UUID>> services_;
534   };
535 
536   // Number that uniquely identifies this device with respect to the bt-host
537   // that generated it.
538   // TODO(armansito): Come up with a scheme that guarnatees the uniqueness of
539   // this ID across all bt-hosts. Today this is guaranteed since we don't allow
540   // clients to interact with multiple controllers simultaneously though this
541   // could possibly lead to collisions if the active adapter gets changed
542   // without clearing the previous adapter's cache.
identifier()543   PeerId identifier() const { return *identifier_; }
544 
545   // The Bluetooth technologies that are supported by this device.
technology()546   TechnologyType technology() const { return *technology_; }
547 
548   // The known device address of this device. Depending on the technologies
549   // supported by this device this has the following meaning:
550   //
551   //   * For BR/EDR devices this is the BD_ADDR.
552   //
553   //   * For LE devices this is identity address IF identity_known() returns
554   //     true. This is always the case if the address type is LE Public.
555   //
556   //     For LE devices that use privacy, identity_known() will be set to false
557   //     upon discovery. The address will be updated only once the identity
558   //     address has been obtained during the pairing procedure.
559   //
560   //   * For BR/EDR/LE devices this is the BD_ADDR and the LE identity address.
561   //     If a BR/EDR/LE device uses an identity address that is different from
562   //     its BD_ADDR, then there will be two separate Peer entries for
563   //     it.
address()564   const DeviceAddress& address() const { return *address_; }
identity_known()565   bool identity_known() const { return identity_known_; }
566 
567   // The LMP version of this device obtained doing discovery.
568   const std::optional<pw::bluetooth::emboss::CoreSpecificationVersion>&
version()569   version() const {
570     return *lmp_version_;
571   }
572 
573   // Returns true if this is a connectable device.
connectable()574   bool connectable() const { return *connectable_; }
575 
576   // Returns true if this device is connected over BR/EDR or LE transports.
connected()577   bool connected() const {
578     return (le() && le()->connected()) || (bredr() && bredr()->connected());
579   }
580 
581   // Returns true if this device has been bonded over BR/EDR or LE transports.
bonded()582   bool bonded() const {
583     return (le() && le()->bonded()) || (bredr() && bredr()->bonded());
584   }
585 
586   // Returns the most recently observed RSSI for this peer. Returns
587   // hci_spec::kRSSIInvalid if the value is unknown.
rssi()588   int8_t rssi() const { return rssi_; }
589 
590   // Gets the user-friendly name of the device, if it's known.
name()591   std::optional<std::string> name() const {
592     return name_->has_value() ? std::optional<std::string>{(*name_)->name}
593                               : std::nullopt;
594   }
595 
596   // Gets the source from which this peer's name was read, if it's known.
name_source()597   std::optional<NameSource> name_source() const {
598     return name_->has_value() ? std::optional<NameSource>{(*name_)->source}
599                               : std::nullopt;
600   }
601 
602   // Gets the appearance of the device, if it's known.
appearance()603   const std::optional<uint16_t>& appearance() const { return appearance_; }
604 
605   // Returns the set of features of this device.
features()606   const hci_spec::LMPFeatureSet& features() const { return *lmp_features_; }
607 
608   // A temporary device gets removed from the PeerCache after a period
609   // of inactivity (see the |update_expiry_callback| argument to the
610   // constructor). The following rules determine the temporary state of a
611   // device:
612   //   a. A device is temporary by default.
613   //   b. A device becomes non-temporary when it gets connected.
614   //   c. A device becomes temporary again when disconnected only if its
615   //      identity is not known (i.e. identity_known() returns false). This only
616   //      applies to LE devices that use the privacy feature.
617   //
618   // Temporary devices are never bonded.
temporary()619   bool temporary() const { return *temporary_; }
620 
621   // Returns the LE transport specific data of this device, if any. This will be
622   // present if information about this device is obtained using the LE discovery
623   // and connection procedures.
le()624   const std::optional<LowEnergyData>& le() const { return le_data_; }
625 
626   // Returns the BR/EDR transport specific data of this device, if any. This
627   // will be present if information about this device is obtained using the
628   // BR/EDR discovery and connection procedures.
bredr()629   const std::optional<BrEdrData>& bredr() const { return bredr_data_; }
630 
631   // Returns a mutable reference to each transport-specific data structure,
632   // initializing the structure if it is unitialized. Use these to mutate
633   // members of the transport-specific structs. The caller must make sure to
634   // invoke these only if the device is known to support said technology.
635   LowEnergyData& MutLe();
636   BrEdrData& MutBrEdr();
637 
638   // Returns a string representation of this device.
639   std::string ToString() const;
640 
641   // The following methods mutate Peer properties:
642 
643   // Updates the name of this device if no name is currently set or if the
644   // source of `name` has higher priority than that of the existing name.
645   // Returns true if a name change occurs.  If the name is updated and
646   // `notify_listeners` is false, then listeners will not be notified of an
647   // update to this peer.
648   bool RegisterName(const std::string& name,
649                     NameSource source = NameSource::kUnknown);
650 
651   // Updates the appearance of this device.
SetAppearance(uint16_t appearance)652   void SetAppearance(uint16_t appearance) { appearance_ = appearance; }
653 
654   // Sets the value of the LMP |features| for the given |page| number.
SetFeaturePage(size_t page,uint64_t features)655   void SetFeaturePage(size_t page, uint64_t features) {
656     lmp_features_.Mutable()->SetPage(page, features);
657   }
658 
659   // Sets the last available LMP feature |page| number for this device.
set_last_page_number(uint8_t page)660   void set_last_page_number(uint8_t page) {
661     lmp_features_.Mutable()->set_last_page_number(page);
662   }
663 
set_version(pw::bluetooth::emboss::CoreSpecificationVersion version,uint16_t manufacturer,uint16_t subversion)664   void set_version(pw::bluetooth::emboss::CoreSpecificationVersion version,
665                    uint16_t manufacturer,
666                    uint16_t subversion) {
667     lmp_version_.Set(version);
668     lmp_manufacturer_.Set(manufacturer);
669     lmp_subversion_ = subversion;
670   }
671 
672   // Marks this device's identity as known. Called by PeerCache when
673   // initializing a bonded device and by LowEnergyData when setting bond data
674   // with an identity address.
set_identity_known(bool value)675   void set_identity_known(bool value) { identity_known_ = value; }
676 
677   // Stores the BR/EDR cross-transport key generated through LE pairing. This
678   // method will not mark the peer as dual-mode if it is not already dual-mode.
679   // It will also not overwrite existing BR/EDR link keys of stronger security
680   // than `ct_key`.
681   void StoreBrEdrCrossTransportKey(sm::LTK ct_key);
682 
683   // Update the connectable status of this peer. This is useful if the peer
684   // sends both non-connectable and connectable advertisements (e.g. when it is
685   // a beacon).
set_connectable(bool connectable)686   void set_connectable(bool connectable) { connectable_.Set(connectable); }
687 
688   // The time when the most recent update occurred. Updates include:
689   // * LE advertising data updated
690   // * LE connection state updated
691   // * LE bond state updated
692   // * BR/EDR connection state updated
693   // * BR/EDR inquiry data updated
694   // * BR/EDR bond data updated
695   // * BR/EDR services updated
696   // * name is updated
last_updated()697   pw::chrono::SystemClock::time_point last_updated() const {
698     return last_updated_;
699   }
700 
701   using WeakPtr = WeakSelf<Peer>::WeakPtr;
GetWeakPtr()702   Peer::WeakPtr GetWeakPtr() { return weak_self_.GetWeakPtr(); }
703 
704  private:
705   struct PeerName {
706     std::string name;
707     NameSource source;
708   };
709 
710   // Assigns a new value for the address of this device. Called by LowEnergyData
711   // when a new identity address is assigned.
set_address(const DeviceAddress & address)712   void set_address(const DeviceAddress& address) { address_.Set(address); }
713 
714   // Updates the RSSI and returns true if it changed.
715   bool SetRssiInternal(int8_t rssi);
716 
717   // Updates the name and returns true if there was a change without notifying
718   // listeners.
719   // TODO(armansito): Add similarly styled internal setters so that we can batch
720   // more updates.
721   bool RegisterNameInternal(const std::string& name, NameSource source);
722 
723   // Marks this device as non-temporary. This operation may fail due to one of
724   // the conditions described above the |temporary()| method.
725   //
726   // TODO(armansito): Replace this with something more sophisticated when we
727   // implement bonding procedures. This method is here to remind us that these
728   // conditions are subtle and not fully supported yet.
729   bool TryMakeNonTemporary();
730 
731   // Marks this device as temporary. This operation may fail due to one of
732   // the conditions described above the |temporary()| method.
733   bool TryMakeTemporary();
734 
735   // Tells the owning PeerCache to update the expiry state of this
736   // device.
737   void UpdateExpiry();
738 
739   // Signal to the cache to notify listeners.
740   void NotifyListeners(NotifyListenersChange change);
741 
742   // Mark this device as dual mode and signal the cache.
743   void MakeDualMode();
744 
745   // Updates the peer last updated timestamp.
746   void OnPeerUpdate();
747 
748   // Updates the peer last updated timestamp an notifies listeners.
749   void UpdatePeerAndNotifyListeners(NotifyListenersChange change);
750 
751   inspect::Node node_;
752 
753   // Callbacks used to notify state changes.
754   NotifyListenersCallback notify_listeners_callback_;
755   PeerCallback update_expiry_callback_;
756   PeerCallback dual_mode_callback_;
757   StoreLowEnergyBondCallback store_le_bond_callback_;
758 
759   StringInspectable<PeerId> identifier_;
760   StringInspectable<TechnologyType> technology_;
761 
762   StringInspectable<DeviceAddress> address_;
763   bool identity_known_;
764 
765   StringInspectable<std::optional<PeerName>> name_;
766   // TODO(fxbug.dev/42177971): Coordinate this field with the appearance read
767   // from advertising data.
768   std::optional<uint16_t> appearance_;
769   StringInspectable<
770       std::optional<pw::bluetooth::emboss::CoreSpecificationVersion>>
771       lmp_version_;
772   StringInspectable<std::optional<uint16_t>> lmp_manufacturer_;
773   std::optional<uint16_t> lmp_subversion_;
774   StringInspectable<hci_spec::LMPFeatureSet> lmp_features_;
775   BoolInspectable<bool> connectable_;
776   BoolInspectable<bool> temporary_;
777   int8_t rssi_;
778 
779   // The spec does not explicitly prohibit LE->BREDR cross-transport key
780   // generation for LE-only peers. This is used to store a CT-generated BR/EDR
781   // key for LE-only peers to avoid incorrectly marking a peer as dual-mode.
782   std::optional<sm::LTK> bredr_cross_transport_key_;
783 
784   // Data that only applies to the LE transport. This is present if this device
785   // is known to support LE.
786   std::optional<LowEnergyData> le_data_;
787 
788   // Data that only applies to the BR/EDR transport. This is present if this
789   // device is known to support BR/EDR.
790   std::optional<BrEdrData> bredr_data_;
791 
792   // Metrics counters used across all peer objects. Weak reference.
793   PeerMetrics* peer_metrics_;
794 
795   // The time when the most recent update occurred.
796   pw::chrono::SystemClock::time_point last_updated_;
797 
798   pw::async::Dispatcher& dispatcher_;
799 
800   WeakSelf<Peer> weak_self_;
801 
802   BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(Peer);
803 };
804 
805 }  // namespace bt::gap
806