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