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