• 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 <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