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