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