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