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