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