1 /*
2 * Copyright 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #pragma once
18
19 namespace bluetooth {
20 namespace hci {
21 namespace acl_manager {
22
23 namespace {
24 class PacketViewForRecombination : public packet::PacketView<kLittleEndian> {
25 public:
PacketViewForRecombination(const PacketView & packetView)26 PacketViewForRecombination(const PacketView& packetView) : PacketView(packetView) {}
AppendPacketView(packet::PacketView<kLittleEndian> to_append)27 void AppendPacketView(packet::PacketView<kLittleEndian> to_append) {
28 Append(to_append);
29 }
30 };
31
32 constexpr size_t kMaxQueuedPacketsPerConnection = 10;
33 constexpr int kL2capBasicFrameHeaderSize = 4;
34
35 // Per spec 5.1 Vol 2 Part B 5.3, ACL link shall carry L2CAP data. Therefore, an ACL packet shall contain L2CAP PDU.
36 // This function returns the PDU size of the L2CAP data if it's a starting packet. Returns 0 if it's invalid.
GetL2capPduSize(AclPacketView packet)37 uint16_t GetL2capPduSize(AclPacketView packet) {
38 auto l2cap_payload = packet.GetPayload();
39 if (l2cap_payload.size() < kL2capBasicFrameHeaderSize) {
40 LOG_ERROR("Controller sent an invalid L2CAP starting packet!");
41 return 0;
42 }
43 return (l2cap_payload.at(1) << 8u) + l2cap_payload.at(0);
44 }
45
46 } // namespace
47
48 struct assembler {
assemblerassembler49 assembler(AddressWithType address_with_type, AclConnection::QueueDownEnd* down_end, os::Handler* handler)
50 : address_with_type_(address_with_type), down_end_(down_end), handler_(handler) {}
51 AddressWithType address_with_type_;
52 AclConnection::QueueDownEnd* down_end_;
53 os::Handler* handler_;
54 PacketViewForRecombination recombination_stage_{PacketView<kLittleEndian>(std::make_shared<std::vector<uint8_t>>())};
55 int remaining_sdu_continuation_packet_size_ = 0;
56 std::shared_ptr<std::atomic_bool> enqueue_registered_ = std::make_shared<std::atomic_bool>(false);
57 std::queue<packet::PacketView<kLittleEndian>> incoming_queue_;
58
~assemblerassembler59 ~assembler() {
60 if (enqueue_registered_->exchange(false)) {
61 down_end_->UnregisterEnqueue();
62 }
63 }
64
65 // Invoked from some external Queue Reactable context
on_le_incoming_data_readyassembler66 std::unique_ptr<packet::PacketView<kLittleEndian>> on_le_incoming_data_ready() {
67 auto packet = incoming_queue_.front();
68 incoming_queue_.pop();
69 if (incoming_queue_.empty() && enqueue_registered_->exchange(false)) {
70 down_end_->UnregisterEnqueue();
71 }
72 return std::make_unique<PacketView<kLittleEndian>>(packet);
73 }
74
on_incoming_packetassembler75 void on_incoming_packet(AclPacketView packet) {
76 PacketView<kLittleEndian> payload = packet.GetPayload();
77 auto payload_size = payload.size();
78 auto packet_boundary_flag = packet.GetPacketBoundaryFlag();
79 if (packet_boundary_flag == PacketBoundaryFlag::FIRST_NON_AUTOMATICALLY_FLUSHABLE) {
80 LOG_ERROR("Controller is not allowed to send FIRST_NON_AUTOMATICALLY_FLUSHABLE to host except loopback mode");
81 return;
82 }
83 if (packet_boundary_flag == PacketBoundaryFlag::CONTINUING_FRAGMENT) {
84 if (remaining_sdu_continuation_packet_size_ < payload_size) {
85 LOG_WARN("Remote sent unexpected L2CAP PDU. Drop the entire L2CAP PDU");
86 recombination_stage_ =
87 PacketViewForRecombination(PacketView<kLittleEndian>(std::make_shared<std::vector<uint8_t>>()));
88 remaining_sdu_continuation_packet_size_ = 0;
89 return;
90 }
91 remaining_sdu_continuation_packet_size_ -= payload_size;
92 recombination_stage_.AppendPacketView(payload);
93 if (remaining_sdu_continuation_packet_size_ != 0) {
94 return;
95 } else {
96 payload = recombination_stage_;
97 recombination_stage_ =
98 PacketViewForRecombination(PacketView<kLittleEndian>(std::make_shared<std::vector<uint8_t>>()));
99 }
100 } else if (packet_boundary_flag == PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE) {
101 if (recombination_stage_.size() > 0) {
102 LOG_ERROR("Controller sent a starting packet without finishing previous packet. Drop previous one.");
103 }
104 auto l2cap_pdu_size = GetL2capPduSize(packet);
105 remaining_sdu_continuation_packet_size_ = l2cap_pdu_size - (payload_size - kL2capBasicFrameHeaderSize);
106 if (remaining_sdu_continuation_packet_size_ > 0) {
107 recombination_stage_ = payload;
108 return;
109 }
110 }
111 if (incoming_queue_.size() > kMaxQueuedPacketsPerConnection) {
112 LOG_ERROR("Dropping packet from %s due to congestion", address_with_type_.ToString().c_str());
113 return;
114 }
115
116 incoming_queue_.push(payload);
117 if (!enqueue_registered_->exchange(true)) {
118 down_end_->RegisterEnqueue(handler_,
119 common::Bind(&assembler::on_le_incoming_data_ready, common::Unretained(this)));
120 }
121 }
122 };
123
124 } // namespace acl_manager
125 } // namespace hci
126 } // namespace bluetooth
127