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