• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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";
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<Request> 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<Request> 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       pairing_state_(std::make_unique<PairingState>(
42           peer_,
43           link_.get(),
44           request_ && request_->AwaitingOutgoing(),
45           std::move(send_auth_request_cb),
46           fit::bind_member<&BrEdrConnection::OnPairingStateStatus>(this))),
47       l2cap_(l2cap),
48       sco_manager_(
49           std::make_unique<sco::ScoConnectionManager>(peer_id_,
50                                                       link_->handle(),
51                                                       link_->peer_address(),
52                                                       link_->local_address(),
53                                                       transport)),
54       interrogator_(new BrEdrInterrogator(
55           peer_, link_->handle(), transport->command_channel()->AsWeakPtr())),
56       create_time_(dispatcher.now()),
57       disconnect_cb_(std::move(disconnect_cb)),
58       peer_init_token_(request_->take_peer_init_token()),
59       peer_conn_token_(peer_->MutBrEdr().RegisterConnection()),
60       dispatcher_(dispatcher) {
61   link_->set_peer_disconnect_callback(
62       [peer_disconnect_cb = std::move(on_peer_disconnect_cb)](
63           const auto& conn, auto /*reason*/) { peer_disconnect_cb(); });
64 }
65 
~BrEdrConnection()66 BrEdrConnection::~BrEdrConnection() {
67   if (auto request = std::exchange(request_, std::nullopt);
68       request.has_value()) {
69     // Connection never completed so signal the requester(s).
70     request->NotifyCallbacks(ToResult(HostError::kNotSupported),
71                              [] { return nullptr; });
72   }
73 
74   sco_manager_.reset();
75   pairing_state_.reset();
76   link_.reset();
77 }
78 
Interrogate(BrEdrInterrogator::ResultCallback callback)79 void BrEdrConnection::Interrogate(BrEdrInterrogator::ResultCallback callback) {
80   interrogator_->Start(std::move(callback));
81 }
82 
OnInterrogationComplete()83 void BrEdrConnection::OnInterrogationComplete() {
84   BT_ASSERT_MSG(!interrogation_complete(),
85                 "%s on a connection that's already been interrogated",
86                 __FUNCTION__);
87 
88   // Fulfill and clear request so that the dtor does not signal requester(s)
89   // with errors.
90   if (auto request = std::exchange(request_, std::nullopt);
91       request.has_value()) {
92     request->NotifyCallbacks(fit::ok(), [this] { return this; });
93   }
94 }
95 
AddRequestCallback(BrEdrConnection::Request::OnComplete cb)96 void BrEdrConnection::AddRequestCallback(
97     BrEdrConnection::Request::OnComplete cb) {
98   if (!request_.has_value()) {
99     cb(fit::ok(), this);
100     return;
101   }
102 
103   BT_ASSERT(request_);
104   request_->AddCallback(std::move(cb));
105 }
106 
OpenL2capChannel(l2cap::Psm psm,l2cap::ChannelParameters params,l2cap::ChannelCallback cb)107 void BrEdrConnection::OpenL2capChannel(l2cap::Psm psm,
108                                        l2cap::ChannelParameters params,
109                                        l2cap::ChannelCallback cb) {
110   if (!interrogation_complete()) {
111     // Connection is not yet ready for L2CAP; return a null channel.
112     bt_log(INFO,
113            "gap-bredr",
114            "connection not ready; canceling connect to PSM %.4x (peer: %s)",
115            psm,
116            bt_str(peer_id_));
117     cb(l2cap::Channel::WeakPtr());
118     return;
119   }
120 
121   bt_log(DEBUG,
122          "gap-bredr",
123          "opening l2cap channel on psm %#.4x (peer: %s)",
124          psm,
125          bt_str(peer_id_));
126   l2cap_->OpenL2capChannel(link().handle(), psm, params, std::move(cb));
127 }
128 
OpenScoConnection(bt::StaticPacket<pw::bluetooth::emboss::SynchronousConnectionParametersWriter> parameters,sco::ScoConnectionManager::OpenConnectionCallback callback)129 BrEdrConnection::ScoRequestHandle BrEdrConnection::OpenScoConnection(
130     bt::StaticPacket<
131         pw::bluetooth::emboss::SynchronousConnectionParametersWriter>
132         parameters,
133     sco::ScoConnectionManager::OpenConnectionCallback callback) {
134   return sco_manager_->OpenConnection(std::move(parameters),
135                                       std::move(callback));
136 }
137 
AcceptScoConnection(std::vector<bt::StaticPacket<pw::bluetooth::emboss::SynchronousConnectionParametersWriter>> parameters,sco::ScoConnectionManager::AcceptConnectionCallback callback)138 BrEdrConnection::ScoRequestHandle BrEdrConnection::AcceptScoConnection(
139     std::vector<bt::StaticPacket<
140         pw::bluetooth::emboss::SynchronousConnectionParametersWriter>>
141         parameters,
142     sco::ScoConnectionManager::AcceptConnectionCallback callback) {
143   return sco_manager_->AcceptConnection(std::move(parameters),
144                                         std::move(callback));
145 }
146 
AttachInspect(inspect::Node & parent,std::string name)147 void BrEdrConnection::AttachInspect(inspect::Node& parent, std::string name) {
148   inspect_node_ = parent.CreateChild(name);
149   inspect_properties_.peer_id = inspect_node_.CreateString(
150       kInspectPeerIdPropertyName, peer_id_.ToString());
151 
152   pairing_state_->AttachInspect(inspect_node_, kInspectPairingStateNodeName);
153 }
154 
OnPairingStateStatus(hci_spec::ConnectionHandle handle,hci::Result<> status)155 void BrEdrConnection::OnPairingStateStatus(hci_spec::ConnectionHandle handle,
156                                            hci::Result<> status) {
157   if (bt_is_error(status,
158                   DEBUG,
159                   "gap-bredr",
160                   "PairingState error status, disconnecting (peer id: %s)",
161                   bt_str(peer_id_))) {
162     if (disconnect_cb_) {
163       disconnect_cb_();
164     }
165     return;
166   }
167 
168   // Once pairing succeeds for the first time, the transition from Initializing
169   // -> Connected can happen.
170   peer_init_token_.reset();
171 }
172 
duration() const173 pw::chrono::SystemClock::duration BrEdrConnection::duration() const {
174   return dispatcher_.now() - create_time_;
175 }
176 
177 }  // namespace bt::gap
178