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/function.h> 17 18 #include <list> 19 20 #include "pw_bluetooth_sapphire/internal/host/common/identifier.h" 21 #include "pw_bluetooth_sapphire/internal/host/common/inspectable.h" 22 #include "pw_bluetooth_sapphire/internal/host/gap/legacy_pairing_state.h" 23 #include "pw_bluetooth_sapphire/internal/host/gap/peer.h" 24 #include "pw_bluetooth_sapphire/internal/host/hci/bredr_connection_request.h" 25 #include "pw_bluetooth_sapphire/internal/host/transport/error.h" 26 27 namespace bt::gap { 28 29 class BrEdrConnection; 30 31 // A |BrEdrConnectionRequest| represents a request for the GAP to connect to a 32 // given |DeviceAddress| by one or more clients. BrEdrConnectionManager is 33 // responsible for tracking ConnectionRequests and passing them to the Connector 34 // when ready. 35 // 36 // There is at most One BrEdrConnectionRequest per address at any given time; if 37 // multiple clients wish to connect, they each append a callback to the list in 38 // the ConnectionRequest for the device they are interested in. 39 // 40 // If a remote peer makes an incoming request for a connection, we track that 41 // here also - whether an incoming request is pending is indicated by 42 // HasIncoming() 43 class BrEdrConnectionRequest final { 44 public: 45 using OnComplete = fit::function<void(hci::Result<>, BrEdrConnection*)>; 46 using OnTimeout = fit::function<void()>; 47 using OnFailure = fit::function<void(hci::Result<>, PeerId)>; 48 using RefFactory = fit::function<BrEdrConnection*()>; 49 50 // Construct without a callback. Can be used for incoming only requests 51 BrEdrConnectionRequest(pw::async::Dispatcher& pw_dispatcher, 52 const DeviceAddress& addr, 53 PeerId peer_id, 54 Peer::InitializingConnectionToken token); 55 56 BrEdrConnectionRequest(pw::async::Dispatcher& pw_dispatcher, 57 const DeviceAddress& addr, 58 PeerId peer_id, 59 Peer::InitializingConnectionToken token, 60 OnComplete&& callback); 61 62 BrEdrConnectionRequest(BrEdrConnectionRequest&&) = default; 63 64 // Creates a hci::BrEdrConnectionRequest from this gap::BrEdrConnectionRequest 65 std::unique_ptr<hci::BrEdrConnectionRequest> CreateHciConnectionRequest( 66 hci::CommandChannel* command_channel, 67 std::optional<uint16_t> clock_offset, 68 std::optional<pw::bluetooth::emboss::PageScanRepetitionMode> 69 page_scan_repetition_mode, 70 OnTimeout timeout_cb, 71 OnFailure failure_cb, 72 pw::async::Dispatcher& dispatcher); 73 74 bool ShouldRetry(hci::Error failure_mode); 75 AddCallback(OnComplete cb)76 void AddCallback(OnComplete cb) { 77 callbacks_.Mutable()->push_back(std::move(cb)); 78 } 79 80 // Notifies all elements in |callbacks| with |status| and the result of 81 // |generate_ref|. Called by the appropriate manager once a connection request 82 // has completed, successfully or otherwise 83 void NotifyCallbacks(hci::Result<> status, const RefFactory& generate_ref); 84 BeginIncoming()85 void BeginIncoming() { has_incoming_.Set(true); } CompleteIncoming()86 void CompleteIncoming() { has_incoming_.Set(false); } HasIncoming()87 bool HasIncoming() const { return *has_incoming_; } AwaitingOutgoing()88 bool AwaitingOutgoing() { return !callbacks_->empty(); } 89 90 // Attach request inspect node as a child of |parent| named |name|. 91 void AttachInspect(inspect::Node& parent, std::string name); 92 address()93 DeviceAddress address() const { return address_; } 94 95 // If a role change occurs while this request is still pending, set it here so 96 // that the correct role is used when connection establishment completes. set_role_change(pw::bluetooth::emboss::ConnectionRole role)97 void set_role_change(pw::bluetooth::emboss::ConnectionRole role) { 98 role_change_ = role; 99 } 100 101 // If the default role of the requested connection is changed during 102 // connection establishment, the new role will be returned. role_change()103 const std::optional<pw::bluetooth::emboss::ConnectionRole>& role_change() 104 const { 105 return role_change_; 106 } 107 set_legacy_pairing_state(std::unique_ptr<LegacyPairingState> legacy_pairing_state)108 void set_legacy_pairing_state( 109 std::unique_ptr<LegacyPairingState> legacy_pairing_state) { 110 legacy_pairing_state_ = std::move(legacy_pairing_state); 111 } legacy_pairing_state()112 LegacyPairingState* legacy_pairing_state() { 113 return legacy_pairing_state_.get(); 114 } take_legacy_pairing_state()115 std::unique_ptr<LegacyPairingState> take_legacy_pairing_state() { 116 return std::move(legacy_pairing_state_); 117 } 118 take_peer_init_token()119 Peer::InitializingConnectionToken take_peer_init_token() { 120 PW_CHECK(peer_init_conn_token_); 121 return std::exchange(peer_init_conn_token_, std::nullopt).value(); 122 } 123 124 private: 125 PeerId peer_id_; 126 DeviceAddress address_; 127 UintInspectable<std::list<OnComplete>> callbacks_; 128 BoolInspectable<bool> has_incoming_{false}; 129 std::optional<pw::bluetooth::emboss::ConnectionRole> role_change_; 130 std::unique_ptr<LegacyPairingState> legacy_pairing_state_; 131 132 // Used to determine whether an outbound connection request should be retried. 133 // If empty, no HCI Create Connection Requests associated with this object 134 // have been made, otherwise stores the time at which the first HCI request 135 // associated with this object was made. 136 IntInspectable<std::optional<pw::chrono::SystemClock::time_point>> 137 first_create_connection_req_made_{ 138 std::nullopt, 139 [](auto& t) { return t ? t->time_since_epoch().count() : -1; }}; 140 141 inspect::StringProperty peer_id_property_; 142 inspect::Node inspect_node_; 143 144 std::optional<Peer::InitializingConnectionToken> peer_init_conn_token_; 145 146 // Time after which a connection attempt is considered to have timed out. 147 pw::chrono::SystemClock::duration request_timeout_{ 148 kBrEdrCreateConnectionTimeout}; 149 150 pw::async::Dispatcher& dispatcher_; 151 152 BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(BrEdrConnectionRequest); 153 }; 154 155 } // namespace bt::gap 156