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