• 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/att/bearer.h"
16 
17 #include <cpp-string/string_printf.h>
18 #include <lib/fit/defer.h>
19 
20 #include <type_traits>
21 
22 #include "pw_bluetooth_sapphire/internal/host/common/log.h"
23 #include "pw_bluetooth_sapphire/internal/host/common/slab_allocator.h"
24 #include "pw_bluetooth_sapphire/internal/host/l2cap/channel.h"
25 #include "pw_bluetooth_sapphire/internal/host/sm/types.h"
26 
27 #pragma clang diagnostic ignored "-Wswitch-enum"
28 
29 namespace bt::att {
30 
31 // static
32 
33 namespace {
34 
35 // Returns the security level that is required to resolve the given ATT error
36 // code and the current security properties of the link, according to the table
37 // in v5.0, Vol 3, Part C, 10.3.2 (table 10.2). A security upgrade is not
38 // required if the returned value equals sm::SecurityLevel::kNoSecurity.
39 // TODO(armansito): Supporting requesting Secure Connections in addition to the
40 // inclusive-language: ignore
41 // encrypted/MITM dimensions.
CheckSecurity(ErrorCode ecode,const sm::SecurityProperties & security)42 sm::SecurityLevel CheckSecurity(ErrorCode ecode,
43                                 const sm::SecurityProperties& security) {
44   bool encrypted = (security.level() != sm::SecurityLevel::kNoSecurity);
45 
46   switch (ecode) {
47     // "Insufficient Encryption" error code is specified for cases when the peer
48     // is paired (i.e. a LTK or STK exists for it) but the link is not
49     // encrypted. We treat this as equivalent to "Insufficient Authentication"
50     // sent on an unencrypted link.
51     case ErrorCode::kInsufficientEncryption:
52       encrypted = false;
53       [[fallthrough]];
54     // We achieve authorization by pairing which requires a confirmation from
55     // the host's pairing delegate.
56     // TODO(armansito): Allow for this to be satisfied with a simple user
57     // confirmation if we're not paired?
58     case ErrorCode::kInsufficientAuthorization:
59     case ErrorCode::kInsufficientAuthentication:
60       // If the link is already authenticated we cannot request a further
61       // upgrade.
62       // TODO(armansito): Take into account "secure connections" once it's
63       // supported.
64       if (security.authenticated()) {
65         return sm::SecurityLevel::kNoSecurity;
66       }
67       return encrypted ? sm::SecurityLevel::kAuthenticated
68                        : sm::SecurityLevel::kEncrypted;
69 
70     // Our SMP implementation always claims to support the maximum encryption
71     // key size. If the key size is too small then the peer must support a
72     // smaller size and we cannot upgrade the key.
73     case ErrorCode::kInsufficientEncryptionKeySize:
74       break;
75     default:
76       break;
77   }
78 
79   return sm::SecurityLevel::kNoSecurity;
80 }
81 
GetMethodType(OpCode opcode)82 MethodType GetMethodType(OpCode opcode) {
83   // We treat all packets as a command if the command bit was set. An
84   // unrecognized command will always be ignored (so it is OK to return kCommand
85   // here if, for example, |opcode| is a response with the command-bit set).
86   if (opcode & kCommandFlag)
87     return MethodType::kCommand;
88 
89   switch (opcode) {
90     case kInvalidOpCode:
91       return MethodType::kInvalid;
92 
93     case kExchangeMTURequest:
94     case kFindInformationRequest:
95     case kFindByTypeValueRequest:
96     case kReadByTypeRequest:
97     case kReadRequest:
98     case kReadBlobRequest:
99     case kReadMultipleRequest:
100     case kReadByGroupTypeRequest:
101     case kWriteRequest:
102     case kPrepareWriteRequest:
103     case kExecuteWriteRequest:
104       return MethodType::kRequest;
105 
106     case kErrorResponse:
107     case kExchangeMTUResponse:
108     case kFindInformationResponse:
109     case kFindByTypeValueResponse:
110     case kReadByTypeResponse:
111     case kReadResponse:
112     case kReadBlobResponse:
113     case kReadMultipleResponse:
114     case kReadByGroupTypeResponse:
115     case kWriteResponse:
116     case kPrepareWriteResponse:
117     case kExecuteWriteResponse:
118       return MethodType::kResponse;
119 
120     case kNotification:
121       return MethodType::kNotification;
122     case kIndication:
123       return MethodType::kIndication;
124     case kConfirmation:
125       return MethodType::kConfirmation;
126 
127     // These are redundant with the check above but are included for
128     // completeness.
129     case kWriteCommand:
130     case kSignedWriteCommand:
131       return MethodType::kCommand;
132 
133     default:
134       break;
135   }
136 
137   // Everything else will be treated as an incoming request.
138   return MethodType::kRequest;
139 }
140 
141 // Returns the corresponding originating transaction opcode for
142 // |transaction_end_code|, where the latter must correspond to a response or
143 // confirmation.
MatchingTransactionCode(OpCode transaction_end_code)144 OpCode MatchingTransactionCode(OpCode transaction_end_code) {
145   switch (transaction_end_code) {
146     case kExchangeMTUResponse:
147       return kExchangeMTURequest;
148     case kFindInformationResponse:
149       return kFindInformationRequest;
150     case kFindByTypeValueResponse:
151       return kFindByTypeValueRequest;
152     case kReadByTypeResponse:
153       return kReadByTypeRequest;
154     case kReadResponse:
155       return kReadRequest;
156     case kReadBlobResponse:
157       return kReadBlobRequest;
158     case kReadMultipleResponse:
159       return kReadMultipleRequest;
160     case kReadByGroupTypeResponse:
161       return kReadByGroupTypeRequest;
162     case kWriteResponse:
163       return kWriteRequest;
164     case kPrepareWriteResponse:
165       return kPrepareWriteRequest;
166     case kExecuteWriteResponse:
167       return kExecuteWriteRequest;
168     case kConfirmation:
169       return kIndication;
170     default:
171       break;
172   }
173 
174   return kInvalidOpCode;
175 }
176 
177 }  // namespace
178 
179 // static
Create(l2cap::Channel::WeakPtr chan,pw::async::Dispatcher & dispatcher)180 std::unique_ptr<Bearer> Bearer::Create(l2cap::Channel::WeakPtr chan,
181                                        pw::async::Dispatcher& dispatcher) {
182   std::unique_ptr<Bearer> bearer(new Bearer(std::move(chan), dispatcher));
183   return bearer->Activate() ? std::move(bearer) : nullptr;
184 }
185 
PendingTransaction(OpCode opcode,TransactionCallback callback,ByteBufferPtr pdu)186 Bearer::PendingTransaction::PendingTransaction(OpCode opcode,
187                                                TransactionCallback callback,
188                                                ByteBufferPtr pdu)
189     : opcode(opcode),
190       callback(std::move(callback)),
191       pdu(std::move(pdu)),
192       security_retry_level(sm::SecurityLevel::kNoSecurity) {
193   BT_ASSERT(this->callback);
194   BT_ASSERT(this->pdu);
195 }
196 
PendingRemoteTransaction(TransactionId id,OpCode opcode)197 Bearer::PendingRemoteTransaction::PendingRemoteTransaction(TransactionId id,
198                                                            OpCode opcode)
199     : id(id), opcode(opcode) {}
200 
TransactionQueue(TransactionQueue && other)201 Bearer::TransactionQueue::TransactionQueue(TransactionQueue&& other)
202     : queue_(std::move(other.queue_)),
203       current_(std::move(other.current_)),
204       timeout_task_(other.timeout_task_.dispatcher()) {
205   // The move constructor is only used during shut down below. So we simply
206   // cancel the task and not worry about moving it.
207   other.timeout_task_.Cancel();
208 }
209 
ClearCurrent()210 Bearer::PendingTransactionPtr Bearer::TransactionQueue::ClearCurrent() {
211   BT_DEBUG_ASSERT(current_);
212   BT_DEBUG_ASSERT(timeout_task_.is_pending());
213 
214   timeout_task_.Cancel();
215 
216   return std::move(current_);
217 }
218 
Enqueue(PendingTransactionPtr transaction)219 void Bearer::TransactionQueue::Enqueue(PendingTransactionPtr transaction) {
220   queue_.push(std::move(transaction));
221 }
222 
TrySendNext(const l2cap::Channel::WeakPtr & chan,pw::async::TaskFunction timeout_cb,pw::chrono::SystemClock::duration timeout)223 void Bearer::TransactionQueue::TrySendNext(
224     const l2cap::Channel::WeakPtr& chan,
225     pw::async::TaskFunction timeout_cb,
226     pw::chrono::SystemClock::duration timeout) {
227   BT_DEBUG_ASSERT(chan.is_alive());
228 
229   // Abort if a transaction is currently pending or there are no transactions
230   // queued.
231   if (current_ || queue_.empty()) {
232     return;
233   }
234 
235   // Advance to the next transaction.
236   current_ = std::move(queue_.front());
237   queue_.pop();
238   while (current()) {
239     BT_DEBUG_ASSERT(!timeout_task_.is_pending());
240     BT_DEBUG_ASSERT(current()->pdu);
241 
242     // We copy the PDU payload in case it needs to be retried following a
243     // security upgrade.
244     auto pdu = NewBuffer(current()->pdu->size());
245     if (pdu) {
246       current()->pdu->Copy(pdu.get());
247       timeout_task_.set_function(std::move(timeout_cb));
248       timeout_task_.PostAfter(timeout);
249       chan->Send(std::move(pdu));
250       break;
251     }
252 
253     bt_log(TRACE, "att", "Failed to start transaction: out of memory!");
254     auto t = std::move(current_);
255     t->callback(
256         fit::error(std::pair(Error(HostError::kOutOfMemory), kInvalidHandle)));
257 
258     // Process the next command until we can send OR we have drained the queue.
259     if (queue_.empty()) {
260       break;
261     }
262     current_ = std::move(queue_.front());
263     queue_.pop();
264   }
265 }
266 
Reset()267 void Bearer::TransactionQueue::Reset() {
268   timeout_task_.Cancel();
269   queue_ = {};
270   current_ = nullptr;
271 }
272 
InvokeErrorAll(Error error)273 void Bearer::TransactionQueue::InvokeErrorAll(Error error) {
274   if (current_) {
275     current_->callback(fit::error(std::pair(error, kInvalidHandle)));
276     current_ = nullptr;
277     timeout_task_.Cancel();
278   }
279 
280   while (!queue_.empty()) {
281     if (queue_.front()->callback) {
282       queue_.front()->callback(fit::error(std::pair(error, kInvalidHandle)));
283     }
284     queue_.pop();
285   }
286 }
287 
Bearer(l2cap::Channel::WeakPtr chan,pw::async::Dispatcher & dispatcher)288 Bearer::Bearer(l2cap::Channel::WeakPtr chan, pw::async::Dispatcher& dispatcher)
289     : dispatcher_(dispatcher),
290       chan_(std::move(chan)),
291       request_queue_(dispatcher_),
292       indication_queue_(dispatcher_),
293       next_remote_transaction_id_(1u),
294       next_handler_id_(1u),
295       weak_self_(this) {
296   BT_DEBUG_ASSERT(chan_);
297 
298   if (chan_->link_type() == bt::LinkType::kLE) {
299     min_mtu_ = kLEMinMTU;
300   } else {
301     min_mtu_ = kBREDRMinMTU;
302   }
303 
304   mtu_ = min_mtu();
305   // TODO(fxbug.dev/42087558): Dynamically configure preferred MTU value.
306   preferred_mtu_ = kLEMaxMTU;
307 }
308 
~Bearer()309 Bearer::~Bearer() {
310   chan_ = nullptr;
311 
312   request_queue_.Reset();
313   indication_queue_.Reset();
314 }
315 
Activate()316 bool Bearer::Activate() {
317   return chan_->Activate(fit::bind_member<&Bearer::OnRxBFrame>(this),
318                          fit::bind_member<&Bearer::OnChannelClosed>(this));
319 }
320 
ShutDown()321 void Bearer::ShutDown() {
322   if (is_open())
323     ShutDownInternal(/*due_to_timeout=*/false);
324 }
325 
ShutDownInternal(bool due_to_timeout)326 void Bearer::ShutDownInternal(bool due_to_timeout) {
327   // Prevent this method from being run twice (e.g. by SignalLinkError() below).
328   if (shut_down_) {
329     return;
330   }
331   BT_ASSERT(is_open());
332   shut_down_ = true;
333 
334   bt_log(DEBUG, "att", "bearer shutting down");
335 
336   // Move the contents to temporaries. This prevents a potential memory
337   // corruption in InvokeErrorAll if the Bearer gets deleted by one of the
338   // invoked error callbacks.
339   TransactionQueue req_queue(std::move(request_queue_));
340   TransactionQueue ind_queue(std::move(indication_queue_));
341 
342   fit::closure closed_cb = std::move(closed_cb_);
343 
344   l2cap::ScopedChannel chan = std::move(chan_);
345   // SignalLinkError may delete the Bearer! Nothing below this line should
346   // access |this|.
347   chan->SignalLinkError();
348   chan = nullptr;
349 
350   if (closed_cb) {
351     closed_cb();
352   }
353 
354   // Terminate all remaining procedures with an error. This is safe even if the
355   // bearer got deleted by |closed_cb_|.
356   Error error(due_to_timeout ? HostError::kTimedOut : HostError::kFailed);
357   req_queue.InvokeErrorAll(error);
358   ind_queue.InvokeErrorAll(error);
359 }
360 
StartTransaction(ByteBufferPtr pdu,TransactionCallback callback)361 void Bearer::StartTransaction(ByteBufferPtr pdu, TransactionCallback callback) {
362   BT_ASSERT(pdu);
363   BT_ASSERT(callback);
364 
365   [[maybe_unused]] bool _ = SendInternal(std::move(pdu), std::move(callback));
366 }
367 
SendWithoutResponse(ByteBufferPtr pdu)368 bool Bearer::SendWithoutResponse(ByteBufferPtr pdu) {
369   BT_ASSERT(pdu);
370   return SendInternal(std::move(pdu), {});
371 }
372 
SendInternal(ByteBufferPtr pdu,TransactionCallback callback)373 bool Bearer::SendInternal(ByteBufferPtr pdu, TransactionCallback callback) {
374   auto _check_callback_empty = fit::defer([&callback]() {
375     // Ensure that callback was either never present or called/moved before
376     // SendInternal returns
377     BT_ASSERT(!callback);
378   });
379 
380   if (!is_open()) {
381     bt_log(TRACE, "att", "bearer closed; cannot send packet");
382     if (callback) {
383       callback(fit::error(
384           std::pair(Error(HostError::kLinkDisconnected), kInvalidHandle)));
385     }
386     return false;
387   }
388 
389   BT_ASSERT_MSG(IsPacketValid(*pdu), "packet has bad length!");
390 
391   PacketReader reader(pdu.get());
392   MethodType type = GetMethodType(reader.opcode());
393 
394   TransactionQueue* tq = nullptr;
395 
396   switch (type) {
397     case MethodType::kCommand:
398     case MethodType::kNotification:
399       BT_ASSERT_MSG(!callback,
400                     "opcode %#.2x has no response but callback was provided",
401                     reader.opcode());
402 
403       // Send the command. No flow control is necessary.
404       chan_->Send(std::move(pdu));
405       return true;
406 
407     case MethodType::kRequest:
408       tq = &request_queue_;
409       break;
410     case MethodType::kIndication:
411       tq = &indication_queue_;
412       break;
413     default:
414       BT_PANIC("unsupported opcode: %#.2x", reader.opcode());
415   }
416 
417   BT_ASSERT_MSG(
418       callback,
419       "transaction with opcode %#.2x has response that requires callback!",
420       reader.opcode());
421 
422   tq->Enqueue(std::make_unique<PendingTransaction>(
423       reader.opcode(), std::move(callback), std::move(pdu)));
424   TryStartNextTransaction(tq);
425 
426   return true;
427 }
428 
RegisterHandler(OpCode opcode,Handler handler)429 Bearer::HandlerId Bearer::RegisterHandler(OpCode opcode, Handler handler) {
430   BT_DEBUG_ASSERT(handler);
431 
432   if (!is_open())
433     return kInvalidHandlerId;
434 
435   if (handlers_.find(opcode) != handlers_.end()) {
436     bt_log(DEBUG,
437            "att",
438            "can only register one handler per opcode (%#.2x)",
439            opcode);
440     return kInvalidHandlerId;
441   }
442 
443   HandlerId id = NextHandlerId();
444   if (id == kInvalidHandlerId)
445     return kInvalidHandlerId;
446 
447   auto res = handler_id_map_.emplace(id, opcode);
448   BT_ASSERT_MSG(res.second, "handler ID got reused (id: %zu)", id);
449 
450   handlers_[opcode] = std::move(handler);
451 
452   return id;
453 }
454 
UnregisterHandler(HandlerId id)455 void Bearer::UnregisterHandler(HandlerId id) {
456   BT_DEBUG_ASSERT(id != kInvalidHandlerId);
457 
458   auto iter = handler_id_map_.find(id);
459   if (iter == handler_id_map_.end()) {
460     bt_log(DEBUG, "att", "cannot unregister unknown handler id: %zu", id);
461     return;
462   }
463 
464   OpCode opcode = iter->second;
465   handlers_.erase(opcode);
466 }
467 
Reply(TransactionId tid,ByteBufferPtr pdu)468 bool Bearer::Reply(TransactionId tid, ByteBufferPtr pdu) {
469   BT_DEBUG_ASSERT(pdu);
470 
471   if (tid == kInvalidTransactionId)
472     return false;
473 
474   if (!is_open()) {
475     bt_log(TRACE, "att", "bearer closed; cannot reply");
476     return false;
477   }
478 
479   if (!IsPacketValid(*pdu)) {
480     bt_log(DEBUG, "att", "invalid response PDU");
481     return false;
482   }
483 
484   RemoteTransaction* pending = FindRemoteTransaction(tid);
485   if (!pending)
486     return false;
487 
488   PacketReader reader(pdu.get());
489 
490   // Use ReplyWithError() instead.
491   if (reader.opcode() == kErrorResponse)
492     return false;
493 
494   OpCode pending_opcode = (*pending)->opcode;
495   if (pending_opcode != MatchingTransactionCode(reader.opcode())) {
496     bt_log(DEBUG,
497            "att",
498            "opcodes do not match (pending: %#.2x, given: %#.2x)",
499            pending_opcode,
500            reader.opcode());
501     return false;
502   }
503 
504   pending->reset();
505   chan_->Send(std::move(pdu));
506 
507   return true;
508 }
509 
ReplyWithError(TransactionId id,Handle handle,ErrorCode error_code)510 bool Bearer::ReplyWithError(TransactionId id,
511                             Handle handle,
512                             ErrorCode error_code) {
513   RemoteTransaction* pending = FindRemoteTransaction(id);
514   if (!pending)
515     return false;
516 
517   OpCode pending_opcode = (*pending)->opcode;
518   if (pending_opcode == kIndication) {
519     bt_log(DEBUG, "att", "cannot respond to an indication with error!");
520     return false;
521   }
522 
523   pending->reset();
524   SendErrorResponse(pending_opcode, handle, error_code);
525 
526   return true;
527 }
528 
IsPacketValid(const ByteBuffer & packet)529 bool Bearer::IsPacketValid(const ByteBuffer& packet) {
530   return packet.size() != 0u && packet.size() <= mtu_;
531 }
532 
TryStartNextTransaction(TransactionQueue * tq)533 void Bearer::TryStartNextTransaction(TransactionQueue* tq) {
534   BT_DEBUG_ASSERT(tq);
535 
536   if (!is_open()) {
537     bt_log(TRACE, "att", "Cannot process transactions; bearer is closed");
538     return;
539   }
540 
541   tq->TrySendNext(
542       chan_.get(),
543       [this](pw::async::Context /*ctx*/, pw::Status status) {
544         if (status.ok()) {
545           ShutDownInternal(/*due_to_timeout=*/true);
546         }
547       },
548       kTransactionTimeout);
549 }
550 
SendErrorResponse(OpCode request_opcode,Handle attribute_handle,ErrorCode error_code)551 void Bearer::SendErrorResponse(OpCode request_opcode,
552                                Handle attribute_handle,
553                                ErrorCode error_code) {
554   auto buffer = NewBuffer(sizeof(Header) + sizeof(ErrorResponseParams));
555   BT_ASSERT(buffer);
556 
557   PacketWriter packet(kErrorResponse, buffer.get());
558   auto* payload = packet.mutable_payload<ErrorResponseParams>();
559   payload->request_opcode = request_opcode;
560   payload->attribute_handle = htole16(attribute_handle);
561   payload->error_code = error_code;
562 
563   chan_->Send(std::move(buffer));
564 }
565 
HandleEndTransaction(TransactionQueue * tq,const PacketReader & packet)566 void Bearer::HandleEndTransaction(TransactionQueue* tq,
567                                   const PacketReader& packet) {
568   BT_DEBUG_ASSERT(is_open());
569   BT_DEBUG_ASSERT(tq);
570 
571   if (!tq->current()) {
572     bt_log(DEBUG,
573            "att",
574            "received unexpected transaction PDU (opcode: %#.2x)",
575            packet.opcode());
576     ShutDown();
577     return;
578   }
579 
580   OpCode target_opcode;
581   std::optional<std::pair<Error, Handle>> error;
582 
583   if (packet.opcode() == kErrorResponse) {
584     // We should never hit this branch for indications.
585     BT_DEBUG_ASSERT(tq->current()->opcode != kIndication);
586 
587     if (packet.payload_size() == sizeof(ErrorResponseParams)) {
588       const auto& payload = packet.payload<ErrorResponseParams>();
589       target_opcode = payload.request_opcode;
590       const ErrorCode error_code = payload.error_code;
591       const Handle attr_in_error = le16toh(payload.attribute_handle);
592       error.emplace(std::pair(Error(error_code), attr_in_error));
593     } else {
594       bt_log(DEBUG, "att", "received malformed error response");
595 
596       // Invalid opcode will fail the opcode comparison below.
597       target_opcode = kInvalidOpCode;
598     }
599   } else {
600     target_opcode = MatchingTransactionCode(packet.opcode());
601   }
602 
603   BT_DEBUG_ASSERT(tq->current()->opcode != kInvalidOpCode);
604 
605   if (tq->current()->opcode != target_opcode) {
606     bt_log(DEBUG,
607            "att",
608            "received bad transaction PDU (opcode: %#.2x)",
609            packet.opcode());
610     ShutDown();
611     return;
612   }
613 
614   // The transaction is complete.
615   auto transaction = tq->ClearCurrent();
616   BT_DEBUG_ASSERT(transaction);
617 
618   const sm::SecurityLevel security_requirement =
619       error.has_value()
620           ? CheckSecurity(error->first.protocol_error(), chan_->security())
621           : sm::SecurityLevel::kNoSecurity;
622   if (transaction->security_retry_level >= security_requirement ||
623       security_requirement <= chan_->security().level()) {
624     // The transaction callback may result in our connection being closed.
625     auto self = weak_self_.GetWeakPtr();
626 
627     // Resolve the transaction.
628     if (error.has_value()) {
629       transaction->callback(fit::error(error.value()));
630     } else {
631       transaction->callback(fit::ok(packet));
632     }
633 
634     if (self.is_alive()) {
635       // Send out the next queued transaction
636       TryStartNextTransaction(tq);
637     }
638     return;
639   }
640 
641   BT_ASSERT(error.has_value());
642   bt_log(TRACE,
643          "att",
644          "Received security error %s for transaction; requesting upgrade to "
645          "level: %s",
646          bt_str(error->first),
647          sm::LevelToString(security_requirement));
648   chan_->UpgradeSecurity(
649       security_requirement,
650       [self = weak_self_.GetWeakPtr(),
651        error = *std::move(error),
652        security_requirement,
653        t = std::move(transaction)](sm::Result<> status) mutable {
654         // If the security upgrade failed or the bearer got destroyed, then
655         // resolve the transaction with the original error.
656         if (!self.is_alive() || status.is_error()) {
657           t->callback(fit::error(std::move(error)));
658           return;
659         }
660 
661         // TODO(armansito): Notify the upper layer to re-initiate service
662         // discovery and other necessary procedures (see Vol 3, Part C,
663         // 10.3.2).
664 
665         // Re-send the request as described in Vol 3, Part G, 8.1. Since |t| was
666         // originally resolved with an Error Response, it must have come out of
667         // |request_queue_|.
668         BT_DEBUG_ASSERT(GetMethodType(t->opcode) == MethodType::kRequest);
669         t->security_retry_level = security_requirement;
670         self->request_queue_.Enqueue(std::move(t));
671         self->TryStartNextTransaction(&self->request_queue_);
672       });
673 
674   // Move on to the next queued transaction.
675   TryStartNextTransaction(tq);
676 }
677 
NextHandlerId()678 Bearer::HandlerId Bearer::NextHandlerId() {
679   auto id = next_handler_id_;
680 
681   // This will stop incrementing if this were overflows and always return
682   // kInvalidHandlerId.
683   if (next_handler_id_ != kInvalidHandlerId)
684     next_handler_id_++;
685   return id;
686 }
687 
NextRemoteTransactionId()688 Bearer::TransactionId Bearer::NextRemoteTransactionId() {
689   auto id = next_remote_transaction_id_;
690 
691   next_remote_transaction_id_++;
692 
693   // Increment extra in the case of overflow.
694   if (next_remote_transaction_id_ == kInvalidTransactionId)
695     next_remote_transaction_id_++;
696 
697   return id;
698 }
699 
HandleBeginTransaction(RemoteTransaction * currently_pending,const PacketReader & packet)700 void Bearer::HandleBeginTransaction(RemoteTransaction* currently_pending,
701                                     const PacketReader& packet) {
702   BT_DEBUG_ASSERT(currently_pending);
703 
704   if (currently_pending->has_value()) {
705     bt_log(DEBUG,
706            "att",
707            "A transaction is already pending! (opcode: %#.2x)",
708            packet.opcode());
709     ShutDown();
710     return;
711   }
712 
713   auto iter = handlers_.find(packet.opcode());
714   if (iter == handlers_.end()) {
715     bt_log(DEBUG,
716            "att",
717            "no handler registered for opcode %#.2x",
718            packet.opcode());
719     SendErrorResponse(packet.opcode(), 0, ErrorCode::kRequestNotSupported);
720     return;
721   }
722 
723   auto id = NextRemoteTransactionId();
724   *currently_pending = PendingRemoteTransaction(id, packet.opcode());
725 
726   iter->second(id, packet);
727 }
728 
FindRemoteTransaction(TransactionId id)729 Bearer::RemoteTransaction* Bearer::FindRemoteTransaction(TransactionId id) {
730   if (remote_request_ && remote_request_->id == id) {
731     return &remote_request_;
732   }
733 
734   if (remote_indication_ && remote_indication_->id == id) {
735     return &remote_indication_;
736   }
737 
738   bt_log(DEBUG, "att", "id %zu does not match any transaction", id);
739   return nullptr;
740 }
741 
HandlePDUWithoutResponse(const PacketReader & packet)742 void Bearer::HandlePDUWithoutResponse(const PacketReader& packet) {
743   auto iter = handlers_.find(packet.opcode());
744   if (iter == handlers_.end()) {
745     bt_log(DEBUG,
746            "att",
747            "dropping unhandled packet (opcode: %#.2x)",
748            packet.opcode());
749     return;
750   }
751 
752   iter->second(kInvalidTransactionId, packet);
753 }
754 
OnChannelClosed()755 void Bearer::OnChannelClosed() {
756   // This will deactivate the channel and notify |closed_cb_|.
757   ShutDown();
758 }
759 
OnRxBFrame(ByteBufferPtr sdu)760 void Bearer::OnRxBFrame(ByteBufferPtr sdu) {
761   BT_DEBUG_ASSERT(sdu);
762   BT_DEBUG_ASSERT(is_open());
763 
764   TRACE_DURATION("bluetooth", "att::Bearer::OnRxBFrame", "length", sdu->size());
765 
766   if (sdu->size() > mtu_) {
767     bt_log(DEBUG, "att", "PDU exceeds MTU!");
768     ShutDown();
769     return;
770   }
771 
772   // This static cast is safe because we have verified that `sdu->size()` fits
773   // in a uint16_t with the above check and the below static_assert.
774   static_assert(std::is_same_v<uint16_t, decltype(mtu_)>);
775   auto length = static_cast<uint16_t>(sdu->size());
776 
777   // An ATT PDU should at least contain the opcode.
778   if (length < sizeof(OpCode)) {
779     bt_log(DEBUG, "att", "PDU too short!");
780     ShutDown();
781     return;
782   }
783 
784   PacketReader packet(sdu.get());
785   switch (GetMethodType(packet.opcode())) {
786     case MethodType::kResponse:
787       HandleEndTransaction(&request_queue_, packet);
788       break;
789     case MethodType::kConfirmation:
790       HandleEndTransaction(&indication_queue_, packet);
791       break;
792     case MethodType::kRequest:
793       HandleBeginTransaction(&remote_request_, packet);
794       break;
795     case MethodType::kIndication:
796       HandleBeginTransaction(&remote_indication_, packet);
797       break;
798     case MethodType::kNotification:
799     case MethodType::kCommand:
800       HandlePDUWithoutResponse(packet);
801       break;
802     default:
803       bt_log(DEBUG, "att", "Unsupported opcode: %#.2x", packet.opcode());
804       SendErrorResponse(packet.opcode(), 0, ErrorCode::kRequestNotSupported);
805       break;
806   }
807 }
808 
809 }  // namespace bt::att
810