• 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_interrogator.h"
16 
17 #include "pw_bluetooth_sapphire/internal/host/common/assert.h"
18 #include "pw_bluetooth_sapphire/internal/host/gap/peer.h"
19 #include "pw_bluetooth_sapphire/internal/host/hci-spec/protocol.h"
20 #include "pw_bluetooth_sapphire/internal/host/transport/command_channel.h"
21 
22 namespace bt::gap {
23 
BrEdrInterrogator(Peer::WeakPtr peer,hci_spec::ConnectionHandle handle,hci::CommandChannel::WeakPtr cmd_channel)24 BrEdrInterrogator::BrEdrInterrogator(Peer::WeakPtr peer,
25                                      hci_spec::ConnectionHandle handle,
26                                      hci::CommandChannel::WeakPtr cmd_channel)
27     : peer_(std::move(peer)),
28       peer_id_(peer_->identifier()),
29       handle_(handle),
30       cmd_runner_(std::move(cmd_channel)),
31       weak_self_(this) {
32   BT_ASSERT(peer_.is_alive());
33 }
34 
Start(ResultCallback callback)35 void BrEdrInterrogator::Start(ResultCallback callback) {
36   callback_ = std::move(callback);
37 
38   if (!peer_.is_alive() || !peer_->bredr()) {
39     Complete(ToResult(HostError::kFailed));
40     return;
41   }
42 
43   if (!peer_->name()) {
44     QueueRemoteNameRequest();
45   }
46 
47   if (!peer_->version()) {
48     QueueReadRemoteVersionInformation();
49   }
50 
51   if (!peer_->features().HasPage(0)) {
52     QueueReadRemoteFeatures();
53   } else if (peer_->features().HasBit(
54                  /*page=*/0, hci_spec::LMPFeature::kExtendedFeatures)) {
55     QueueReadRemoteExtendedFeatures(/*page=*/1);
56   }
57 
58   if (!cmd_runner_.HasQueuedCommands()) {
59     Complete(fit::ok());
60     return;
61   }
62 
63   cmd_runner_.RunCommands([this](hci::Result<> result) { Complete(result); });
64 }
65 
Cancel()66 void BrEdrInterrogator::Cancel() {
67   if (!cmd_runner_.IsReady()) {
68     cmd_runner_.Cancel();
69   }
70 }
71 
Complete(hci::Result<> result)72 void BrEdrInterrogator::Complete(hci::Result<> result) {
73   if (!callback_) {
74     return;
75   }
76 
77   auto self = weak_self_.GetWeakPtr();
78 
79   // callback may destroy this object
80   callback_(result);
81 
82   if (self.is_alive() && !cmd_runner_.IsReady()) {
83     cmd_runner_.Cancel();
84   }
85 }
86 
QueueRemoteNameRequest()87 void BrEdrInterrogator::QueueRemoteNameRequest() {
88   pw::bluetooth::emboss::PageScanRepetitionMode mode =
89       pw::bluetooth::emboss::PageScanRepetitionMode::R0_;
90   if (peer_->bredr()->page_scan_repetition_mode()) {
91     mode = *peer_->bredr()->page_scan_repetition_mode();
92   }
93 
94   auto packet = hci::EmbossCommandPacket::New<
95       pw::bluetooth::emboss::RemoteNameRequestCommandWriter>(
96       hci_spec::kRemoteNameRequest);
97   auto params = packet.view_t();
98   params.bd_addr().CopyFrom(peer_->address().value().view());
99   params.page_scan_repetition_mode().Write(mode);
100   if (peer_->bredr()->clock_offset()) {
101     params.clock_offset().valid().Write(true);
102     const uint16_t offset = peer_->bredr()->clock_offset().value();
103     params.clock_offset().clock_offset().Write(offset);
104   }
105 
106   auto cmd_cb = [this](const hci::EmbossEventPacket& event) {
107     if (hci_is_error(event, WARN, "gap-bredr", "remote name request failed")) {
108       return;
109     }
110     bt_log(TRACE,
111            "gap-bredr",
112            "name request complete (peer id: %s)",
113            bt_str(peer_id_));
114 
115     auto params =
116         event.view<pw::bluetooth::emboss::RemoteNameRequestCompleteEventView>();
117     emboss::support::ReadOnlyContiguousBuffer name =
118         params.remote_name().BackingStorage();
119     const unsigned char* name_end = std::find(name.begin(), name.end(), '\0');
120     std::string name_string(reinterpret_cast<const char*>(name.begin()),
121                             reinterpret_cast<const char*>(name_end));
122     peer_->RegisterName(std::move(name_string),
123                         Peer::NameSource::kNameDiscoveryProcedure);
124   };
125 
126   bt_log(TRACE,
127          "gap-bredr",
128          "sending name request (peer id: %s)",
129          bt_str(peer_->identifier()));
130   cmd_runner_.QueueCommand(std::move(packet),
131                            std::move(cmd_cb),
132                            /*wait=*/false,
133                            hci_spec::kRemoteNameRequestCompleteEventCode,
134                            {hci_spec::kInquiry});
135 }
136 
QueueReadRemoteFeatures()137 void BrEdrInterrogator::QueueReadRemoteFeatures() {
138   auto packet = hci::EmbossCommandPacket::New<
139       pw::bluetooth::emboss::ReadRemoteSupportedFeaturesCommandWriter>(
140       hci_spec::kReadRemoteSupportedFeatures);
141   packet.view_t().connection_handle().Write(handle_);
142 
143   auto cmd_cb = [this](const hci::EventPacket& event) {
144     if (hci_is_error(event,
145                      WARN,
146                      "gap-bredr",
147                      "read remote supported features failed")) {
148       return;
149     }
150     bt_log(TRACE,
151            "gap-bredr",
152            "remote features request complete (peer id: %s)",
153            bt_str(peer_id_));
154     const auto& params =
155         event.view()
156             .payload<
157                 hci_spec::ReadRemoteSupportedFeaturesCompleteEventParams>();
158     peer_->SetFeaturePage(0, le64toh(params.lmp_features));
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::EmbossCommandPacket::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::EmbossEventPacket& 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::EmbossCommandPacket::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::EmbossEventPacket& event) {
247     if (hci_is_error(event, WARN, "gap", "read remote version info failed")) {
248       return;
249     }
250     BT_DEBUG_ASSERT(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