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/transport/command_channel.h"
16
17 #include <cpp-string/string_printf.h>
18 #include <endian.h>
19 #include <lib/fit/defer.h>
20 #include <pw_bluetooth/hci_android.emb.h>
21 #include <pw_bluetooth/hci_common.emb.h>
22
23 #include "pw_bluetooth_sapphire/internal/host/common/assert.h"
24 #include "pw_bluetooth_sapphire/internal/host/common/log.h"
25 #include "pw_bluetooth_sapphire/internal/host/common/trace.h"
26 #include "pw_bluetooth_sapphire/internal/host/transport/slab_allocators.h"
27
28 namespace bt::hci {
29
30 namespace {
31
32 // Helper for std::variant
33 template <class... Ts>
34 struct overloaded : Ts... {
35 using Ts::operator()...;
36 };
37 // explicit deduction guide (not needed in C++20)
38 template <class... Ts>
39 overloaded(Ts...) -> overloaded<Ts...>;
40
41 } // namespace
42
IsAsync(hci_spec::EventCode code)43 static bool IsAsync(hci_spec::EventCode code) {
44 return code != hci_spec::kCommandCompleteEventCode &&
45 code != hci_spec::kCommandStatusEventCode;
46 }
47
EventTypeToString(CommandChannel::EventType event_type)48 static std::string EventTypeToString(CommandChannel::EventType event_type) {
49 switch (event_type) {
50 case CommandChannel::EventType::kHciEvent:
51 return "hci_event";
52 case CommandChannel::EventType::kLEMetaEvent:
53 return "le_meta_event";
54 case CommandChannel::EventType::kVendorEvent:
55 return "vendor_event";
56 }
57 }
58
QueuedCommand(CommandPacketVariant command_packet,std::unique_ptr<TransactionData> transaction_data)59 CommandChannel::QueuedCommand::QueuedCommand(
60 CommandPacketVariant command_packet,
61 std::unique_ptr<TransactionData> transaction_data)
62 : packet(std::move(command_packet)), data(std::move(transaction_data)) {
63 BT_DEBUG_ASSERT(data);
64 }
65
TransactionData(CommandChannel * channel,TransactionId transaction_id,hci_spec::OpCode opcode,hci_spec::EventCode complete_event_code,std::optional<hci_spec::EventCode> le_meta_subevent_code,std::unordered_set<hci_spec::OpCode> exclusions,CommandCallbackVariant callback)66 CommandChannel::TransactionData::TransactionData(
67 CommandChannel* channel,
68 TransactionId transaction_id,
69 hci_spec::OpCode opcode,
70 hci_spec::EventCode complete_event_code,
71 std::optional<hci_spec::EventCode> le_meta_subevent_code,
72 std::unordered_set<hci_spec::OpCode> exclusions,
73 CommandCallbackVariant callback)
74 : channel_(channel),
75 transaction_id_(transaction_id),
76 opcode_(opcode),
77 complete_event_code_(complete_event_code),
78 le_meta_subevent_code_(le_meta_subevent_code),
79 exclusions_(std::move(exclusions)),
80 callback_(std::move(callback)),
81 timeout_task_(channel_->dispatcher_),
82 handler_id_(0u) {
83 BT_DEBUG_ASSERT(transaction_id != 0u);
84 exclusions_.insert(opcode_);
85 }
86
~TransactionData()87 CommandChannel::TransactionData::~TransactionData() {
88 std::visit(
89 [this](auto& cb) {
90 if (cb) {
91 bt_log(DEBUG,
92 "hci",
93 "destroying unfinished transaction: %zu",
94 transaction_id_);
95 }
96 },
97 callback_);
98 }
99
StartTimer()100 void CommandChannel::TransactionData::StartTimer() {
101 // Transactions should only ever be started once.
102 BT_DEBUG_ASSERT(!timeout_task_.is_pending());
103 timeout_task_.set_function(
104 [chan = channel_, tid = id()](auto, pw::Status status) {
105 if (status.ok()) {
106 chan->OnCommandTimeout(tid);
107 }
108 });
109 timeout_task_.PostAfter(hci_spec::kCommandTimeout);
110 }
111
Complete(std::unique_ptr<EventPacket> event)112 void CommandChannel::TransactionData::Complete(
113 std::unique_ptr<EventPacket> event) {
114 timeout_task_.Cancel();
115
116 std::visit(
117 [this, &event](auto& cb) {
118 using T = std::decay_t<decltype(cb)>;
119
120 if (!cb) {
121 return;
122 }
123
124 // Call callback_ synchronously to ensure that asynchronous status &
125 // complete events are not handled out of order if they are dispatched
126 // from the HCI API simultaneously.
127 if constexpr (std::is_same_v<T, CommandCallback>) {
128 cb(transaction_id_, *event);
129 } else {
130 EmbossEventPacket packet =
131 EmbossEventPacket::New(event->view().size());
132 MutableBufferView view = packet.mutable_data();
133 event->view().data().Copy(&view);
134 cb(transaction_id_, packet);
135 }
136
137 // Asynchronous commands will have an additional reference to callback_
138 // in the event map. Clear this reference to ensure that destruction or
139 // unexpected command complete events or status events do not call this
140 // reference to callback_ twice.
141 cb = nullptr;
142 },
143 callback_);
144 }
145
Cancel()146 void CommandChannel::TransactionData::Cancel() {
147 timeout_task_.Cancel();
148 std::visit([](auto& cb) { cb = nullptr; }, callback_);
149 }
150
151 CommandChannel::EventCallbackVariant
MakeCallback()152 CommandChannel::TransactionData::MakeCallback() {
153 return std::visit(
154 overloaded{[this](CommandCallback& cb) -> EventCallbackVariant {
155 return [transaction_id = transaction_id_,
156 cb = cb.share()](const EventPacket& event) {
157 cb(transaction_id, event);
158 return EventCallbackResult::kContinue;
159 };
160 },
161 [this](EmbossCommandCallback& cb) -> EventCallbackVariant {
162 return [transaction_id = transaction_id_,
163 cb = cb.share()](const EmbossEventPacket& event) {
164 cb(transaction_id, event);
165 return EventCallbackResult::kContinue;
166 };
167 }},
168 callback_);
169 }
170
CommandChannel(pw::bluetooth::Controller * hci,pw::async::Dispatcher & dispatcher)171 CommandChannel::CommandChannel(pw::bluetooth::Controller* hci,
172 pw::async::Dispatcher& dispatcher)
173 : next_transaction_id_(1u),
174 next_event_handler_id_(1u),
175 hci_(hci),
176 allowed_command_packets_(1u),
177 dispatcher_(dispatcher),
178 weak_ptr_factory_(this) {
179 hci_->SetEventFunction(fit::bind_member<&CommandChannel::OnEvent>(this));
180
181 bt_log(DEBUG, "hci", "CommandChannel initialized");
182 }
183
~CommandChannel()184 CommandChannel::~CommandChannel() {
185 bt_log(INFO, "hci", "CommandChannel destroyed");
186 hci_->SetEventFunction(nullptr);
187 }
188
SendCommand(CommandPacketVariant command_packet,CommandCallback callback,const hci_spec::EventCode complete_event_code)189 CommandChannel::TransactionId CommandChannel::SendCommand(
190 CommandPacketVariant command_packet,
191 CommandCallback callback,
192 const hci_spec::EventCode complete_event_code) {
193 return SendExclusiveCommand(
194 std::move(command_packet), std::move(callback), complete_event_code);
195 }
196
SendLeAsyncCommand(CommandPacketVariant command_packet,CommandCallback callback,hci_spec::EventCode le_meta_subevent_code)197 CommandChannel::TransactionId CommandChannel::SendLeAsyncCommand(
198 CommandPacketVariant command_packet,
199 CommandCallback callback,
200 hci_spec::EventCode le_meta_subevent_code) {
201 return SendLeAsyncExclusiveCommand(
202 std::move(command_packet), std::move(callback), le_meta_subevent_code);
203 }
204
SendExclusiveCommand(CommandPacketVariant command_packet,CommandCallbackVariant callback,const hci_spec::EventCode complete_event_code,std::unordered_set<hci_spec::OpCode> exclusions)205 CommandChannel::TransactionId CommandChannel::SendExclusiveCommand(
206 CommandPacketVariant command_packet,
207 CommandCallbackVariant callback,
208 const hci_spec::EventCode complete_event_code,
209 std::unordered_set<hci_spec::OpCode> exclusions) {
210 return SendExclusiveCommandInternal(std::move(command_packet),
211 std::move(callback),
212 complete_event_code,
213 std::nullopt,
214 std::move(exclusions));
215 }
216
SendLeAsyncExclusiveCommand(CommandPacketVariant command_packet,CommandCallback callback,std::optional<hci_spec::EventCode> le_meta_subevent_code,std::unordered_set<hci_spec::OpCode> exclusions)217 CommandChannel::TransactionId CommandChannel::SendLeAsyncExclusiveCommand(
218 CommandPacketVariant command_packet,
219 CommandCallback callback,
220 std::optional<hci_spec::EventCode> le_meta_subevent_code,
221 std::unordered_set<hci_spec::OpCode> exclusions) {
222 return SendExclusiveCommandInternal(std::move(command_packet),
223 std::move(callback),
224 hci_spec::kLEMetaEventCode,
225 le_meta_subevent_code,
226 std::move(exclusions));
227 }
228
SendExclusiveCommandInternal(CommandPacketVariant command_packet,CommandCallbackVariant callback,hci_spec::EventCode complete_event_code,std::optional<hci_spec::EventCode> le_meta_subevent_code,std::unordered_set<hci_spec::OpCode> exclusions)229 CommandChannel::TransactionId CommandChannel::SendExclusiveCommandInternal(
230 CommandPacketVariant command_packet,
231 CommandCallbackVariant callback,
232 hci_spec::EventCode complete_event_code,
233 std::optional<hci_spec::EventCode> le_meta_subevent_code,
234 std::unordered_set<hci_spec::OpCode> exclusions) {
235 if (!active_) {
236 bt_log(INFO, "hci", "ignoring command (CommandChannel is inactive)");
237 return 0;
238 }
239
240 BT_ASSERT_MSG((complete_event_code == hci_spec::kLEMetaEventCode) ==
241 le_meta_subevent_code.has_value(),
242 "only LE Meta Event subevents are supported");
243
244 if (IsAsync(complete_event_code)) {
245 // Cannot send an asynchronous command if there's an external event handler
246 // registered for the completion event.
247 EventHandlerData* handler = nullptr;
248 if (le_meta_subevent_code.has_value()) {
249 handler = FindLEMetaEventHandler(*le_meta_subevent_code);
250 } else {
251 handler = FindEventHandler(complete_event_code);
252 }
253
254 if (handler && !handler->is_async()) {
255 bt_log(DEBUG, "hci", "event handler already handling this event");
256 return 0u;
257 }
258 }
259
260 if (next_transaction_id_.value() == 0u) {
261 next_transaction_id_.Set(1);
262 }
263
264 const hci_spec::OpCode opcode = std::visit(
265 overloaded{[](std::unique_ptr<CommandPacket>& p) { return p->opcode(); },
266 [](EmbossCommandPacket& p) { return p.opcode(); }},
267 command_packet);
268 const TransactionId transaction_id = next_transaction_id_.value();
269 next_transaction_id_.Set(transaction_id + 1);
270
271 std::unique_ptr<CommandChannel::TransactionData> data =
272 std::make_unique<TransactionData>(this,
273 transaction_id,
274 opcode,
275 complete_event_code,
276 le_meta_subevent_code,
277 std::move(exclusions),
278 std::move(callback));
279
280 QueuedCommand command(std::move(command_packet), std::move(data));
281
282 if (IsAsync(complete_event_code)) {
283 MaybeAddTransactionHandler(command.data.get());
284 }
285
286 send_queue_.push_back(std::move(command));
287 TrySendQueuedCommands();
288
289 return transaction_id;
290 }
291
RemoveQueuedCommand(TransactionId transaction_id)292 bool CommandChannel::RemoveQueuedCommand(TransactionId transaction_id) {
293 auto it = std::find_if(send_queue_.begin(),
294 send_queue_.end(),
295 [transaction_id](const QueuedCommand& cmd) {
296 return cmd.data->id() == transaction_id;
297 });
298 if (it == send_queue_.end()) {
299 // The transaction to remove has already finished or never existed.
300 bt_log(
301 TRACE, "hci", "command to remove not found, id: %zu", transaction_id);
302 return false;
303 }
304
305 bt_log(TRACE, "hci", "removing queued command id: %zu", transaction_id);
306 TransactionData& data = *it->data;
307 data.Cancel();
308
309 RemoveEventHandlerInternal(data.handler_id());
310 send_queue_.erase(it);
311 return true;
312 }
313
AddEventHandler(hci_spec::EventCode event_code,EventCallbackVariant event_callback_variant)314 CommandChannel::EventHandlerId CommandChannel::AddEventHandler(
315 hci_spec::EventCode event_code,
316 EventCallbackVariant event_callback_variant) {
317 if (event_code == hci_spec::kCommandStatusEventCode ||
318 event_code == hci_spec::kCommandCompleteEventCode ||
319 event_code == hci_spec::kLEMetaEventCode) {
320 return 0u;
321 }
322
323 EventHandlerData* handler = FindEventHandler(event_code);
324 if (handler && handler->is_async()) {
325 bt_log(ERROR,
326 "hci",
327 "async event handler %zu already registered for event code %#.2x",
328 handler->handler_id,
329 event_code);
330 return 0u;
331 }
332
333 EventHandlerId handler_id =
334 NewEventHandler(event_code,
335 EventType::kHciEvent,
336 hci_spec::kNoOp,
337 std::move(event_callback_variant));
338 event_code_handlers_.emplace(event_code, handler_id);
339 return handler_id;
340 }
341
AddLEMetaEventHandler(hci_spec::EventCode le_meta_subevent_code,EventCallbackVariant event_callback)342 CommandChannel::EventHandlerId CommandChannel::AddLEMetaEventHandler(
343 hci_spec::EventCode le_meta_subevent_code,
344 EventCallbackVariant event_callback) {
345 EventHandlerData* handler = FindLEMetaEventHandler(le_meta_subevent_code);
346 if (handler && handler->is_async()) {
347 bt_log(ERROR,
348 "hci",
349 "async event handler %zu already registered for LE Meta Event "
350 "subevent code %#.2x",
351 handler->handler_id,
352 le_meta_subevent_code);
353 return 0u;
354 }
355
356 EventHandlerId handler_id = NewEventHandler(le_meta_subevent_code,
357 EventType::kLEMetaEvent,
358 hci_spec::kNoOp,
359 std::move(event_callback));
360 le_meta_subevent_code_handlers_.emplace(le_meta_subevent_code, handler_id);
361 return handler_id;
362 }
363
AddVendorEventHandler(hci_spec::EventCode vendor_subevent_code,EventCallbackVariant event_callback)364 CommandChannel::EventHandlerId CommandChannel::AddVendorEventHandler(
365 hci_spec::EventCode vendor_subevent_code,
366 EventCallbackVariant event_callback) {
367 CommandChannel::EventHandlerData* handler =
368 FindVendorEventHandler(vendor_subevent_code);
369 if (handler && handler->is_async()) {
370 bt_log(ERROR,
371 "hci",
372 "async event handler %zu already registered for Vendor Event "
373 "subevent code %#.2x",
374 handler->handler_id,
375 vendor_subevent_code);
376 return 0u;
377 }
378
379 EventHandlerId handler_id = NewEventHandler(vendor_subevent_code,
380 EventType::kVendorEvent,
381 hci_spec::kNoOp,
382 std::move(event_callback));
383 vendor_subevent_code_handlers_.emplace(vendor_subevent_code, handler_id);
384 return handler_id;
385 }
386
RemoveEventHandler(EventHandlerId handler_id)387 void CommandChannel::RemoveEventHandler(EventHandlerId handler_id) {
388 // If the ID doesn't exist or it is internal. it can't be removed.
389 auto iter = event_handler_id_map_.find(handler_id);
390 if (iter == event_handler_id_map_.end() || iter->second.is_async()) {
391 return;
392 }
393
394 RemoveEventHandlerInternal(handler_id);
395 }
396
FindEventHandler(hci_spec::EventCode code)397 CommandChannel::EventHandlerData* CommandChannel::FindEventHandler(
398 hci_spec::EventCode code) {
399 auto it = event_code_handlers_.find(code);
400 if (it == event_code_handlers_.end()) {
401 return nullptr;
402 }
403 return &event_handler_id_map_[it->second];
404 }
405
FindLEMetaEventHandler(hci_spec::EventCode le_meta_subevent_code)406 CommandChannel::EventHandlerData* CommandChannel::FindLEMetaEventHandler(
407 hci_spec::EventCode le_meta_subevent_code) {
408 auto it = le_meta_subevent_code_handlers_.find(le_meta_subevent_code);
409 if (it == le_meta_subevent_code_handlers_.end()) {
410 return nullptr;
411 }
412 return &event_handler_id_map_[it->second];
413 }
414
FindVendorEventHandler(hci_spec::EventCode vendor_subevent_code)415 CommandChannel::EventHandlerData* CommandChannel::FindVendorEventHandler(
416 hci_spec::EventCode vendor_subevent_code) {
417 auto it = vendor_subevent_code_handlers_.find(vendor_subevent_code);
418 if (it == vendor_subevent_code_handlers_.end()) {
419 return nullptr;
420 }
421
422 return &event_handler_id_map_[it->second];
423 }
424
RemoveEventHandlerInternal(EventHandlerId handler_id)425 void CommandChannel::RemoveEventHandlerInternal(EventHandlerId handler_id) {
426 auto iter = event_handler_id_map_.find(handler_id);
427 if (iter == event_handler_id_map_.end()) {
428 return;
429 }
430
431 std::unordered_multimap<hci_spec::EventCode, EventHandlerId>* handlers =
432 nullptr;
433 switch (iter->second.event_type) {
434 case EventType::kHciEvent:
435 handlers = &event_code_handlers_;
436 break;
437 case EventType::kLEMetaEvent:
438 handlers = &le_meta_subevent_code_handlers_;
439 break;
440 case EventType::kVendorEvent:
441 handlers = &vendor_subevent_code_handlers_;
442 break;
443 }
444
445 bt_log(TRACE,
446 "hci",
447 "removing handler for %s event code %#.2x",
448 EventTypeToString(iter->second.event_type).c_str(),
449 iter->second.event_code);
450
451 auto range = handlers->equal_range(iter->second.event_code);
452 for (auto it = range.first; it != range.second; ++it) {
453 if (it->second == handler_id) {
454 it = handlers->erase(it);
455 break;
456 }
457 }
458
459 event_handler_id_map_.erase(iter);
460 }
461
TrySendQueuedCommands()462 void CommandChannel::TrySendQueuedCommands() {
463 if (allowed_command_packets_.value() == 0) {
464 bt_log(TRACE, "hci", "controller queue full, waiting");
465 return;
466 }
467
468 // Walk the waiting and see if any are sendable.
469 for (auto it = send_queue_.begin();
470 allowed_command_packets_.value() > 0 && it != send_queue_.end();) {
471 // Care must be taken not to dangle this reference if its owner
472 // QueuedCommand is destroyed.
473 const TransactionData& data = *it->data;
474
475 // Can't send if another is running with an opcode this can't coexist with.
476 bool excluded = false;
477 for (hci_spec::OpCode excluded_opcode : data.exclusions()) {
478 if (pending_transactions_.count(excluded_opcode) != 0) {
479 bt_log(TRACE,
480 "hci",
481 "pending command (%#.4x) delayed due to running opcode %#.4x",
482 it->data->opcode(),
483 excluded_opcode);
484 excluded = true;
485 break;
486 }
487 }
488 if (excluded) {
489 ++it;
490 continue;
491 }
492
493 bool transaction_waiting_on_event =
494 event_code_handlers_.count(data.complete_event_code());
495 bool transaction_waiting_on_subevent =
496 data.le_meta_subevent_code() &&
497 le_meta_subevent_code_handlers_.count(*data.le_meta_subevent_code());
498 bool waiting_for_other_transaction =
499 transaction_waiting_on_event || transaction_waiting_on_subevent;
500
501 // We can send this if we only expect one update, or if we aren't waiting
502 // for another transaction to complete on the same event. It is unlikely but
503 // possible to have commands with different opcodes wait on the same
504 // completion event.
505 if (!IsAsync(data.complete_event_code()) || data.handler_id() != 0 ||
506 !waiting_for_other_transaction) {
507 bt_log(
508 TRACE, "hci", "sending previously queued command id %zu", data.id());
509 SendQueuedCommand(std::move(*it));
510 it = send_queue_.erase(it);
511 continue;
512 }
513 ++it;
514 }
515 }
516
SendQueuedCommand(QueuedCommand && cmd)517 void CommandChannel::SendQueuedCommand(QueuedCommand&& cmd) {
518 pw::span packet_span = std::visit(
519 overloaded{[](std::unique_ptr<CommandPacket>& p) {
520 return p->view().data().subspan();
521 },
522 [](EmbossCommandPacket& p) { return p.data().subspan(); }},
523 cmd.packet);
524 hci_->SendCommand(packet_span);
525
526 allowed_command_packets_.Set(allowed_command_packets_.value() - 1);
527
528 std::unique_ptr<TransactionData>& transaction = cmd.data;
529
530 transaction->StartTimer();
531
532 MaybeAddTransactionHandler(transaction.get());
533
534 pending_transactions_.insert(
535 std::make_pair(transaction->opcode(), std::move(transaction)));
536 }
537
MaybeAddTransactionHandler(TransactionData * data)538 void CommandChannel::MaybeAddTransactionHandler(TransactionData* data) {
539 // We don't need to add a transaction handler for synchronous transactions.
540 if (!IsAsync(data->complete_event_code())) {
541 return;
542 }
543
544 EventType event_type = EventType::kHciEvent;
545 std::unordered_multimap<hci_spec::EventCode, EventHandlerId>* handlers =
546 nullptr;
547
548 if (data->le_meta_subevent_code().has_value()) {
549 event_type = EventType::kLEMetaEvent;
550 handlers = &le_meta_subevent_code_handlers_;
551 } else {
552 event_type = EventType::kHciEvent;
553 handlers = &event_code_handlers_;
554 }
555
556 const hci_spec::EventCode code =
557 data->le_meta_subevent_code().value_or(data->complete_event_code());
558
559 // We already have a handler for this transaction, or another transaction is
560 // already waiting and it will be queued.
561 if (handlers->count(code)) {
562 bt_log(TRACE, "hci", "async command %zu: already has handler", data->id());
563 return;
564 }
565
566 EventHandlerId handler_id =
567 NewEventHandler(code, event_type, data->opcode(), data->MakeCallback());
568
569 BT_ASSERT(handler_id != 0u);
570 data->set_handler_id(handler_id);
571 handlers->emplace(code, handler_id);
572 bt_log(TRACE,
573 "hci",
574 "async command %zu assigned handler %zu",
575 data->id(),
576 handler_id);
577 }
578
NewEventHandler(hci_spec::EventCode event_code,EventType event_type,hci_spec::OpCode pending_opcode,EventCallbackVariant event_callback_variant)579 CommandChannel::EventHandlerId CommandChannel::NewEventHandler(
580 hci_spec::EventCode event_code,
581 EventType event_type,
582 hci_spec::OpCode pending_opcode,
583 EventCallbackVariant event_callback_variant) {
584 BT_DEBUG_ASSERT(event_code);
585 BT_DEBUG_ASSERT(
586 (std::holds_alternative<EventCallback>(event_callback_variant) &&
587 std::get<EventCallback>(event_callback_variant)) ||
588 (std::holds_alternative<EmbossEventCallback>(event_callback_variant) &&
589 std::get<EmbossEventCallback>(event_callback_variant)));
590
591 auto handler_id = next_event_handler_id_.value();
592 next_event_handler_id_.Set(handler_id + 1);
593 EventHandlerData data;
594 data.handler_id = handler_id;
595 data.event_code = event_code;
596 data.event_type = event_type;
597 data.pending_opcode = pending_opcode;
598 data.event_callback = std::move(event_callback_variant);
599
600 bt_log(TRACE,
601 "hci",
602 "adding event handler %zu for %s event code %#.2x",
603 handler_id,
604 EventTypeToString(event_type).c_str(),
605 event_code);
606 BT_DEBUG_ASSERT(event_handler_id_map_.find(handler_id) ==
607 event_handler_id_map_.end());
608 event_handler_id_map_[handler_id] = std::move(data);
609
610 return handler_id;
611 }
612
UpdateTransaction(std::unique_ptr<EventPacket> event)613 void CommandChannel::UpdateTransaction(std::unique_ptr<EventPacket> event) {
614 hci_spec::EventCode event_code = event->event_code();
615
616 BT_DEBUG_ASSERT(event_code == hci_spec::kCommandStatusEventCode ||
617 event_code == hci_spec::kCommandCompleteEventCode);
618
619 hci_spec::OpCode matching_opcode;
620
621 // The HCI Command Status event with an error status might indicate that an
622 // async command failed. We use this to unregister async command handlers
623 // below.
624 bool unregister_async_handler = false;
625
626 if (event->event_code() == hci_spec::kCommandCompleteEventCode) {
627 const hci_spec::CommandCompleteEventParams& params =
628 event->params<hci_spec::CommandCompleteEventParams>();
629 matching_opcode = le16toh(params.command_opcode);
630 allowed_command_packets_.Set(params.num_hci_command_packets);
631 } else { // hci_spec::kCommandStatusEventCode
632 const hci_spec::CommandStatusEventParams& params =
633 event->params<hci_spec::CommandStatusEventParams>();
634 matching_opcode = le16toh(params.command_opcode);
635 allowed_command_packets_.Set(params.num_hci_command_packets);
636 unregister_async_handler =
637 params.status != pw::bluetooth::emboss::StatusCode::SUCCESS;
638 }
639 bt_log(TRACE,
640 "hci",
641 "allowed packets update: %zu",
642 allowed_command_packets_.value());
643
644 if (matching_opcode == hci_spec::kNoOp) {
645 return;
646 }
647
648 auto it = pending_transactions_.find(matching_opcode);
649 if (it == pending_transactions_.end()) {
650 bt_log(
651 ERROR, "hci", "update for unexpected opcode: %#.4x", matching_opcode);
652 return;
653 }
654
655 std::unique_ptr<TransactionData>& transaction_ref = it->second;
656 BT_DEBUG_ASSERT(transaction_ref->opcode() == matching_opcode);
657
658 // If the command is synchronous or there's no handler to cleanup, we're done.
659 if (transaction_ref->handler_id() == 0u) {
660 std::unique_ptr<TransactionData> transaction = std::move(it->second);
661 pending_transactions_.erase(it);
662 transaction->Complete(std::move(event));
663 return;
664 }
665
666 // TODO(fxbug.dev/42062242): Do not allow asynchronous commands to finish with
667 // Command Complete.
668 if (event_code == hci_spec::kCommandCompleteEventCode) {
669 bt_log(WARN, "hci", "async command received CommandComplete");
670 unregister_async_handler = true;
671 }
672
673 // If an asynchronous command failed, then remove its event handler.
674 if (unregister_async_handler) {
675 bt_log(TRACE, "hci", "async command failed; removing its handler");
676 RemoveEventHandlerInternal(transaction_ref->handler_id());
677 std::unique_ptr<TransactionData> transaction = std::move(it->second);
678 pending_transactions_.erase(it);
679 transaction->Complete(std::move(event));
680 } else {
681 // Send the status event to the async transaction.
682 transaction_ref->Complete(std::move(event));
683 }
684 }
685
NotifyEventHandler(std::unique_ptr<EventPacket> event)686 void CommandChannel::NotifyEventHandler(std::unique_ptr<EventPacket> event) {
687 struct PendingCallback {
688 EventCallbackVariant callback_variant;
689 EventHandlerId handler_id;
690 };
691 std::vector<PendingCallback> pending_callbacks;
692
693 hci_spec::EventCode event_code;
694 const std::unordered_multimap<hci_spec::EventCode, EventHandlerId>*
695 event_handlers;
696
697 EventType event_type;
698 switch (event->event_code()) {
699 case hci_spec::kLEMetaEventCode:
700 event_type = EventType::kLEMetaEvent;
701 event_code = event->params<hci_spec::LEMetaEventParams>().subevent_code;
702 event_handlers = &le_meta_subevent_code_handlers_;
703 break;
704 case hci_spec::kVendorDebugEventCode:
705 event_type = EventType::kVendorEvent;
706 event_code = pw::bluetooth::emboss::MakeVendorDebugEventView(
707 event->view().data().data(), event->view().size())
708 .subevent_code()
709 .Read();
710 event_handlers = &vendor_subevent_code_handlers_;
711 break;
712 default:
713 event_type = EventType::kHciEvent;
714 event_code = event->event_code();
715 event_handlers = &event_code_handlers_;
716 break;
717 }
718
719 auto range = event_handlers->equal_range(event_code);
720 if (range.first == range.second) {
721 bt_log(DEBUG,
722 "hci",
723 "%s event %#.2x received with no handler",
724 EventTypeToString(event_type).c_str(),
725 event_code);
726 return;
727 }
728
729 auto iter = range.first;
730 while (iter != range.second) {
731 EventHandlerId event_id = iter->second;
732 bt_log(TRACE,
733 "hci",
734 "notifying handler (id %zu) for event code %#.2x",
735 event_id,
736 event_code);
737 auto handler_iter = event_handler_id_map_.find(event_id);
738 BT_DEBUG_ASSERT(handler_iter != event_handler_id_map_.end());
739
740 EventHandlerData& handler = handler_iter->second;
741 BT_DEBUG_ASSERT(handler.event_code == event_code);
742
743 std::visit(
744 [&pending_callbacks, event_id](auto& callback) {
745 pending_callbacks.push_back({callback.share(), event_id});
746 },
747 handler.event_callback);
748
749 ++iter; // Advance so we don't point to an invalid iterator.
750 if (handler.is_async()) {
751 bt_log(TRACE,
752 "hci",
753 "removing completed async handler (id %zu, event code: %#.2x)",
754 event_id,
755 event_code);
756 pending_transactions_.erase(handler.pending_opcode);
757 RemoveEventHandlerInternal(event_id); // |handler| is now dangling.
758 }
759 }
760
761 // Process queue so callbacks can't add a handler if another queued command
762 // finishes on the same event.
763 TrySendQueuedCommands();
764
765 EventPacket& event_packet = *event;
766 for (auto it = pending_callbacks.begin(); it != pending_callbacks.end();
767 ++it) {
768 // Execute the event callback.
769 EventCallbackResult result = std::visit(
770 overloaded{[&event_packet](EventCallback& callback) {
771 return callback(event_packet);
772 },
773 [&event_packet](EmbossEventCallback& callback) {
774 auto emboss_packet =
775 EmbossEventPacket::New(event_packet.view().size());
776 bt::MutableBufferView dest = emboss_packet.mutable_data();
777 event_packet.view().data().Copy(&dest);
778 return callback(emboss_packet);
779 }},
780 it->callback_variant);
781
782 if (result == EventCallbackResult::kRemove) {
783 RemoveEventHandler(it->handler_id);
784 }
785 }
786 }
787
OnEvent(pw::span<const std::byte> buffer)788 void CommandChannel::OnEvent(pw::span<const std::byte> buffer) {
789 if (!active_) {
790 bt_log(INFO, "hci", "ignoring event (CommandChannel is inactive)");
791 return;
792 }
793
794 if (buffer.size() < sizeof(hci_spec::EventHeader)) {
795 // TODO(fxbug.dev/42179582): Handle these types of errors by signaling
796 // Transport.
797 bt_log(ERROR,
798 "hci",
799 "malformed packet - expected at least %zu bytes, got %zu",
800 sizeof(hci_spec::EventHeader),
801 buffer.size());
802 return;
803 }
804
805 const size_t payload_size = buffer.size() - sizeof(hci_spec::EventHeader);
806
807 std::unique_ptr<EventPacket> event = EventPacket::New(payload_size);
808 event->mutable_view()->mutable_data().Write(
809 reinterpret_cast<const uint8_t*>(buffer.data()), buffer.size());
810 event->InitializeFromBuffer();
811
812 if (event->view().header().parameter_total_size != payload_size) {
813 // TODO(fxbug.dev/42179582): Handle these types of errors by signaling
814 // Transport.
815 bt_log(ERROR,
816 "hci",
817 "malformed packet - payload size from header (%hu) does not match"
818 " received payload size: %zu",
819 event->view().header().parameter_total_size,
820 payload_size);
821 return;
822 }
823
824 if (event->event_code() == hci_spec::kCommandStatusEventCode ||
825 event->event_code() == hci_spec::kCommandCompleteEventCode) {
826 UpdateTransaction(std::move(event));
827 TrySendQueuedCommands();
828 } else {
829 NotifyEventHandler(std::move(event));
830 }
831 }
832
OnCommandTimeout(TransactionId transaction_id)833 void CommandChannel::OnCommandTimeout(TransactionId transaction_id) {
834 if (!active_) {
835 return;
836 }
837 bt_log(
838 ERROR, "hci", "command %zu timed out, notifying error", transaction_id);
839 active_ = false;
840 if (channel_timeout_cb_) {
841 fit::closure cb = std::move(channel_timeout_cb_);
842 // The callback may destroy CommandChannel, so no state should be accessed
843 // after this line.
844 cb();
845 }
846 }
847
AttachInspect(inspect::Node & parent,const std::string & name)848 void CommandChannel::AttachInspect(inspect::Node& parent,
849 const std::string& name) {
850 command_channel_node_ = parent.CreateChild(name);
851 next_transaction_id_.AttachInspect(command_channel_node_,
852 "next_transaction_id");
853 next_event_handler_id_.AttachInspect(command_channel_node_,
854 "next_event_handler_id");
855 allowed_command_packets_.AttachInspect(command_channel_node_,
856 "allowed_command_packets");
857 }
858
859 } // namespace bt::hci
860