xref: /aosp_15_r20/external/pigweed/pw_bluetooth_sapphire/host/gap/bredr_interrogator.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_interrogator.h"
16 
17 #include <pw_bytes/endian.h>
18 
19 #include "pw_bluetooth_sapphire/internal/host/common/assert.h"
20 #include "pw_bluetooth_sapphire/internal/host/gap/peer.h"
21 #include "pw_bluetooth_sapphire/internal/host/hci-spec/protocol.h"
22 #include "pw_bluetooth_sapphire/internal/host/transport/command_channel.h"
23 
24 namespace bt::gap {
25 
BrEdrInterrogator(Peer::WeakPtr peer,hci_spec::ConnectionHandle handle,hci::CommandChannel::WeakPtr cmd_channel)26 BrEdrInterrogator::BrEdrInterrogator(Peer::WeakPtr peer,
27                                      hci_spec::ConnectionHandle handle,
28                                      hci::CommandChannel::WeakPtr cmd_channel)
29     : peer_(std::move(peer)),
30       peer_id_(peer_->identifier()),
31       handle_(handle),
32       cmd_runner_(std::move(cmd_channel)),
33       weak_self_(this) {
34   PW_CHECK(peer_.is_alive());
35 }
36 
Start(ResultCallback callback)37 void BrEdrInterrogator::Start(ResultCallback callback) {
38   callback_ = std::move(callback);
39 
40   if (!peer_.is_alive() || !peer_->bredr()) {
41     Complete(ToResult(HostError::kFailed));
42     return;
43   }
44 
45   if (!peer_->name()) {
46     QueueRemoteNameRequest();
47   }
48 
49   if (!peer_->version()) {
50     QueueReadRemoteVersionInformation();
51   }
52 
53   if (!peer_->features().HasPage(0)) {
54     QueueReadRemoteFeatures();
55   } else if (peer_->features().HasBit(
56                  /*page=*/0, hci_spec::LMPFeature::kExtendedFeatures)) {
57     QueueReadRemoteExtendedFeatures(/*page=*/1);
58   }
59 
60   if (!cmd_runner_.HasQueuedCommands()) {
61     Complete(fit::ok());
62     return;
63   }
64 
65   cmd_runner_.RunCommands([this](hci::Result<> result) { Complete(result); });
66 }
67 
Cancel()68 void BrEdrInterrogator::Cancel() {
69   if (!cmd_runner_.IsReady()) {
70     cmd_runner_.Cancel();
71   }
72 }
73 
Complete(hci::Result<> result)74 void BrEdrInterrogator::Complete(hci::Result<> result) {
75   if (!callback_) {
76     return;
77   }
78 
79   auto self = weak_self_.GetWeakPtr();
80 
81   // callback may destroy this object
82   callback_(result);
83 
84   if (self.is_alive() && !cmd_runner_.IsReady()) {
85     cmd_runner_.Cancel();
86   }
87 }
88 
QueueRemoteNameRequest()89 void BrEdrInterrogator::QueueRemoteNameRequest() {
90   pw::bluetooth::emboss::PageScanRepetitionMode mode =
91       pw::bluetooth::emboss::PageScanRepetitionMode::R0_;
92   if (peer_->bredr()->page_scan_repetition_mode()) {
93     mode = *peer_->bredr()->page_scan_repetition_mode();
94   }
95 
96   auto packet = hci::CommandPacket::New<
97       pw::bluetooth::emboss::RemoteNameRequestCommandWriter>(
98       hci_spec::kRemoteNameRequest);
99   auto packet_view = packet.view_t();
100   packet_view.bd_addr().CopyFrom(peer_->address().value().view());
101   packet_view.page_scan_repetition_mode().Write(mode);
102   if (peer_->bredr()->clock_offset()) {
103     packet_view.clock_offset().valid().Write(true);
104     const uint16_t offset = peer_->bredr()->clock_offset().value();
105     packet_view.clock_offset().clock_offset().Write(offset);
106   }
107 
108   auto cmd_cb = [this](const hci::EventPacket& event) {
109     if (HCI_IS_ERROR(event, WARN, "gap-bredr", "remote name request failed")) {
110       return;
111     }
112     bt_log(TRACE,
113            "gap-bredr",
114            "name request complete (peer id: %s)",
115            bt_str(peer_id_));
116 
117     auto params =
118         event.view<pw::bluetooth::emboss::RemoteNameRequestCompleteEventView>();
119     emboss::support::ReadOnlyContiguousBuffer name =
120         params.remote_name().BackingStorage();
121     const unsigned char* name_end = std::find(name.begin(), name.end(), '\0');
122     std::string name_string(reinterpret_cast<const char*>(name.begin()),
123                             reinterpret_cast<const char*>(name_end));
124     peer_->RegisterName(std::move(name_string),
125                         Peer::NameSource::kNameDiscoveryProcedure);
126   };
127 
128   bt_log(TRACE,
129          "gap-bredr",
130          "sending name request (peer id: %s)",
131          bt_str(peer_->identifier()));
132   cmd_runner_.QueueCommand(std::move(packet),
133                            std::move(cmd_cb),
134                            /*wait=*/false,
135                            hci_spec::kRemoteNameRequestCompleteEventCode,
136                            {hci_spec::kInquiry});
137 }
138 
QueueReadRemoteFeatures()139 void BrEdrInterrogator::QueueReadRemoteFeatures() {
140   auto packet = hci::CommandPacket::New<
141       pw::bluetooth::emboss::ReadRemoteSupportedFeaturesCommandWriter>(
142       hci_spec::kReadRemoteSupportedFeatures);
143   packet.view_t().connection_handle().Write(handle_);
144 
145   auto cmd_cb = [this](const hci::EventPacket& event) {
146     if (HCI_IS_ERROR(event,
147                      WARN,
148                      "gap-bredr",
149                      "read remote supported features failed")) {
150       return;
151     }
152     bt_log(TRACE,
153            "gap-bredr",
154            "remote features request complete (peer id: %s)",
155            bt_str(peer_id_));
156     auto view = event.view<
157         pw::bluetooth::emboss::ReadRemoteSupportedFeaturesCompleteEventView>();
158     peer_->SetFeaturePage(0, view.lmp_features().BackingStorage().ReadUInt());
159 
160     if (peer_->features().HasBit(/*page=*/0,
161                                  hci_spec::LMPFeature::kExtendedFeatures)) {
162       peer_->set_last_page_number(1);
163       QueueReadRemoteExtendedFeatures(/*page=*/1);
164     }
165   };
166 
167   bt_log(TRACE,
168          "gap-bredr",
169          "asking for supported features (peer id: %s)",
170          bt_str(peer_id_));
171   cmd_runner_.QueueCommand(
172       std::move(packet),
173       std::move(cmd_cb),
174       /*wait=*/false,
175       hci_spec::kReadRemoteSupportedFeaturesCompleteEventCode);
176 }
177 
QueueReadRemoteExtendedFeatures(uint8_t page)178 void BrEdrInterrogator::QueueReadRemoteExtendedFeatures(uint8_t page) {
179   auto packet = hci::CommandPacket::New<
180       pw::bluetooth::emboss::ReadRemoteExtendedFeaturesCommandWriter>(
181       hci_spec::kReadRemoteExtendedFeatures);
182   auto params = packet.view_t();
183   params.connection_handle().Write(handle_);
184   params.page_number().Write(page);
185 
186   auto cmd_cb = [this, page](const hci::EventPacket& event) {
187     if (HCI_IS_ERROR(event,
188                      WARN,
189                      "gap-bredr",
190                      "read remote extended features failed (peer id: %s)",
191                      bt_str(peer_id_))) {
192       return;
193     }
194     auto view = event.view<
195         pw::bluetooth::emboss::ReadRemoteExtendedFeaturesCompleteEventView>();
196 
197     bt_log(TRACE,
198            "gap-bredr",
199            "got extended features page %u, max page %u (requested page: %u, "
200            "peer id: %s)",
201            view.page_number().Read(),
202            view.max_page_number().Read(),
203            page,
204            bt_str(peer_id_));
205 
206     peer_->SetFeaturePage(view.page_number().Read(),
207                           view.lmp_features().BackingStorage().ReadUInt());
208 
209     if (view.page_number().Read() != page) {
210       bt_log(INFO,
211              "gap-bredr",
212              "requested page %u and got page %u, giving up (peer: %s)",
213              page,
214              view.page_number().Read(),
215              bt_str(peer_id_));
216       peer_->set_last_page_number(0);
217       return;
218     }
219 
220     // NOTE: last page number will be capped at 2
221     peer_->set_last_page_number(view.max_page_number().Read());
222 
223     if (page < peer_->features().last_page_number()) {
224       QueueReadRemoteExtendedFeatures(page + 1);
225     }
226   };
227 
228   bt_log(TRACE,
229          "gap-bredr",
230          "requesting extended features page %u (peer id: %s)",
231          page,
232          bt_str(peer_id_));
233   cmd_runner_.QueueCommand(
234       std::move(packet),
235       std::move(cmd_cb),
236       /*wait=*/false,
237       hci_spec::kReadRemoteExtendedFeaturesCompleteEventCode);
238 }
239 
QueueReadRemoteVersionInformation()240 void BrEdrInterrogator::QueueReadRemoteVersionInformation() {
241   auto packet = hci::CommandPacket::New<
242       pw::bluetooth::emboss::ReadRemoteVersionInfoCommandWriter>(
243       hci_spec::kReadRemoteVersionInfo);
244   packet.view_t().connection_handle().Write(handle_);
245 
246   auto cmd_cb = [this](const hci::EventPacket& event) {
247     if (HCI_IS_ERROR(event, WARN, "gap", "read remote version info failed")) {
248       return;
249     }
250     PW_DCHECK(event.event_code() ==
251               hci_spec::kReadRemoteVersionInfoCompleteEventCode);
252     bt_log(TRACE,
253            "gap",
254            "read remote version info completed (peer id: %s)",
255            bt_str(peer_id_));
256     auto view = event.view<
257         pw::bluetooth::emboss::ReadRemoteVersionInfoCompleteEventView>();
258     peer_->set_version(view.version().Read(),
259                        view.company_identifier().Read(),
260                        view.subversion().Read());
261   };
262 
263   bt_log(
264       TRACE, "gap", "asking for version info (peer id: %s)", bt_str(peer_id_));
265   cmd_runner_.QueueCommand(std::move(packet),
266                            std::move(cmd_cb),
267                            /*wait=*/false,
268                            hci_spec::kReadRemoteVersionInfoCompleteEventCode);
269 }
270 
271 }  // namespace bt::gap
272