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 #include "pw_bluetooth_sapphire/internal/host/gap/bredr_connection.h"
16
17 #include <pw_assert/check.h>
18
19 #include <utility>
20
21 namespace bt::gap {
22
23 namespace {
24
25 const char* const kInspectPeerIdPropertyName = "peer_id";
26 const char* const kInspectPairingStateNodeName = "pairing_state_manager";
27
28 } // namespace
29
BrEdrConnection(Peer::WeakPtr peer,std::unique_ptr<hci::BrEdrConnection> link,fit::closure send_auth_request_cb,fit::callback<void ()> disconnect_cb,fit::closure on_peer_disconnect_cb,l2cap::ChannelManager * l2cap,hci::Transport::WeakPtr transport,std::optional<BrEdrConnectionRequest> request,hci::LocalAddressDelegate * low_energy_address_delegate,bool controller_remote_public_key_validation_supported,sm::BrEdrSecurityManagerFactory security_manager_factory,pw::async::Dispatcher & dispatcher)30 BrEdrConnection::BrEdrConnection(
31 Peer::WeakPtr peer,
32 std::unique_ptr<hci::BrEdrConnection> link,
33 fit::closure send_auth_request_cb,
34 fit::callback<void()> disconnect_cb,
35 fit::closure on_peer_disconnect_cb,
36 l2cap::ChannelManager* l2cap,
37 hci::Transport::WeakPtr transport,
38 std::optional<BrEdrConnectionRequest> request,
39 hci::LocalAddressDelegate* low_energy_address_delegate,
40 bool controller_remote_public_key_validation_supported,
41 sm::BrEdrSecurityManagerFactory security_manager_factory,
42 pw::async::Dispatcher& dispatcher)
43 : peer_id_(peer->identifier()),
44 peer_(std::move(peer)),
45 link_(std::move(link)),
46 request_(std::move(request)),
47 controller_remote_public_key_validation_supported_(
48 controller_remote_public_key_validation_supported),
49 security_manager_factory_(std::move(security_manager_factory)),
50 l2cap_(l2cap),
51 sco_manager_(
52 std::make_unique<sco::ScoConnectionManager>(peer_id_,
53 link_->handle(),
54 link_->peer_address(),
55 link_->local_address(),
56 transport)),
57 interrogator_(new BrEdrInterrogator(
58 peer_, link_->handle(), transport->command_channel()->AsWeakPtr())),
59 create_time_(dispatcher.now()),
60 disconnect_cb_(std::move(disconnect_cb)),
61 peer_init_token_(request_->take_peer_init_token()),
62 peer_conn_token_(peer_->MutBrEdr().RegisterConnection()),
63 dispatcher_(dispatcher) {
64 link_->set_peer_disconnect_callback(
65 [peer_disconnect_cb = std::move(on_peer_disconnect_cb)](
66 const auto&, auto) { peer_disconnect_cb(); });
67
68 std::unique_ptr<LegacyPairingState> legacy_pairing_state = nullptr;
69 if (request_ && request_->legacy_pairing_state()) {
70 // This means that we were responding to Legacy Pairing before the
71 // ACL connection between the two devices was complete.
72 legacy_pairing_state = request_->take_legacy_pairing_state();
73
74 // TODO(fxbug.dev/356165942): Check that legacy pairing is done
75 }
76
77 pairing_state_manager_ = std::make_unique<PairingStateManager>(
78 peer_,
79 link_->GetWeakPtr(),
80 std::move(legacy_pairing_state),
81 request_ && request_->AwaitingOutgoing(),
82 std::move(send_auth_request_cb),
83 fit::bind_member<&BrEdrConnection::OnPairingStateStatus>(this),
84 low_energy_address_delegate,
85 controller_remote_public_key_validation_supported_,
86 security_manager_factory_,
87 dispatcher_);
88 }
89
~BrEdrConnection()90 BrEdrConnection::~BrEdrConnection() {
91 if (auto request = std::exchange(request_, std::nullopt);
92 request.has_value()) {
93 // Connection never completed so signal the requester(s).
94 request->NotifyCallbacks(ToResult(HostError::kNotSupported),
95 [] { return nullptr; });
96 }
97
98 sco_manager_.reset();
99 pairing_state_manager_.reset();
100 link_.reset();
101 }
102
Interrogate(BrEdrInterrogator::ResultCallback callback)103 void BrEdrConnection::Interrogate(BrEdrInterrogator::ResultCallback callback) {
104 interrogator_->Start(std::move(callback));
105 }
106
OnInterrogationComplete()107 void BrEdrConnection::OnInterrogationComplete() {
108 PW_CHECK(!interrogation_complete(),
109 "%s on a connection that's already been interrogated",
110 __FUNCTION__);
111
112 // Fulfill and clear request so that the dtor does not signal requester(s)
113 // with errors.
114 if (auto request = std::exchange(request_, std::nullopt);
115 request.has_value()) {
116 request->NotifyCallbacks(fit::ok(), [this] { return this; });
117 }
118 }
119
AddRequestCallback(BrEdrConnectionRequest::OnComplete cb)120 void BrEdrConnection::AddRequestCallback(
121 BrEdrConnectionRequest::OnComplete cb) {
122 if (!request_.has_value()) {
123 cb(fit::ok(), this);
124 return;
125 }
126
127 PW_CHECK(request_);
128 request_->AddCallback(std::move(cb));
129 }
130
CreateOrUpdatePairingState(PairingStateType type,const PairingDelegate::WeakPtr & pairing_delegate,BrEdrSecurityMode security_mode)131 void BrEdrConnection::CreateOrUpdatePairingState(
132 PairingStateType type,
133 const PairingDelegate::WeakPtr& pairing_delegate,
134 BrEdrSecurityMode security_mode) {
135 PW_CHECK(pairing_state_manager_);
136 pairing_state_manager_->CreateOrUpdatePairingState(type, pairing_delegate);
137 set_security_mode(security_mode);
138 }
139
OpenL2capChannel(l2cap::Psm psm,l2cap::ChannelParameters params,l2cap::ChannelCallback cb)140 void BrEdrConnection::OpenL2capChannel(l2cap::Psm psm,
141 l2cap::ChannelParameters params,
142 l2cap::ChannelCallback cb) {
143 if (!interrogation_complete()) {
144 // Connection is not yet ready for L2CAP; return a null channel.
145 bt_log(INFO,
146 "gap-bredr",
147 "connection not ready; canceling connect to PSM %.4x (peer: %s)",
148 psm,
149 bt_str(peer_id_));
150 cb(l2cap::Channel::WeakPtr());
151 return;
152 }
153
154 bt_log(DEBUG,
155 "gap-bredr",
156 "opening l2cap channel on psm %#.4x (peer: %s)",
157 psm,
158 bt_str(peer_id_));
159 l2cap_->OpenL2capChannel(link().handle(), psm, params, std::move(cb));
160 }
161
OpenScoConnection(bt::StaticPacket<pw::bluetooth::emboss::SynchronousConnectionParametersWriter> parameters,sco::ScoConnectionManager::OpenConnectionCallback callback)162 BrEdrConnection::ScoRequestHandle BrEdrConnection::OpenScoConnection(
163 bt::StaticPacket<
164 pw::bluetooth::emboss::SynchronousConnectionParametersWriter>
165 parameters,
166 sco::ScoConnectionManager::OpenConnectionCallback callback) {
167 return sco_manager_->OpenConnection(std::move(parameters),
168 std::move(callback));
169 }
170
AcceptScoConnection(std::vector<bt::StaticPacket<pw::bluetooth::emboss::SynchronousConnectionParametersWriter>> parameters,sco::ScoConnectionManager::AcceptConnectionCallback callback)171 BrEdrConnection::ScoRequestHandle BrEdrConnection::AcceptScoConnection(
172 std::vector<bt::StaticPacket<
173 pw::bluetooth::emboss::SynchronousConnectionParametersWriter>>
174 parameters,
175 sco::ScoConnectionManager::AcceptConnectionCallback callback) {
176 return sco_manager_->AcceptConnection(std::move(parameters),
177 std::move(callback));
178 }
179
AttachInspect(inspect::Node & parent,std::string name)180 void BrEdrConnection::AttachInspect(inspect::Node& parent, std::string name) {
181 inspect_node_ = parent.CreateChild(name);
182 inspect_properties_.peer_id = inspect_node_.CreateString(
183 kInspectPeerIdPropertyName, peer_id_.ToString());
184
185 pairing_state_manager_->AttachInspect(inspect_node_,
186 kInspectPairingStateNodeName);
187 }
188
OnPairingStateStatus(hci_spec::ConnectionHandle,hci::Result<> status)189 void BrEdrConnection::OnPairingStateStatus(hci_spec::ConnectionHandle,
190 hci::Result<> status) {
191 if (bt_is_error(
192 status,
193 DEBUG,
194 "gap-bredr",
195 "SecureSimplePairingState error status, disconnecting (peer id: %s)",
196 bt_str(peer_id_))) {
197 if (disconnect_cb_) {
198 disconnect_cb_();
199 }
200 return;
201 }
202
203 // Once pairing succeeds for the first time, the transition from Initializing
204 // -> Connected can happen.
205 peer_init_token_.reset();
206 }
207
duration() const208 pw::chrono::SystemClock::duration BrEdrConnection::duration() const {
209 return dispatcher_.now() - create_time_;
210 }
211
SetSecurityManagerChannel(l2cap::Channel::WeakPtr security_manager_channel)212 void BrEdrConnection::SetSecurityManagerChannel(
213 l2cap::Channel::WeakPtr security_manager_channel) {
214 if (!pairing_state_manager_->secure_simple_pairing_state()) {
215 bt_log(DEBUG,
216 "gap-bredr",
217 "dropping SMP channel because SecureSimplePairingState not in use");
218 return;
219 }
220 pairing_state_manager_->secure_simple_pairing_state()
221 ->SetSecurityManagerChannel(std::move(security_manager_channel));
222 }
223
224 } // namespace bt::gap
225