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(AclView packet)37 uint16_t GetL2capPduSize(AclView 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(AclView packet) {
76 PacketView<kLittleEndian> payload = packet.GetPayload();
77 auto payload_size = payload.size();
78 auto broadcast_flag = packet.GetBroadcastFlag();
79 if (broadcast_flag == BroadcastFlag::ACTIVE_PERIPHERAL_BROADCAST) {
80 LOG_WARN("Dropping broadcast from remote");
81 return;
82 }
83 auto packet_boundary_flag = packet.GetPacketBoundaryFlag();
84 if (packet_boundary_flag == PacketBoundaryFlag::FIRST_NON_AUTOMATICALLY_FLUSHABLE) {
85 LOG_ERROR("Controller is not allowed to send FIRST_NON_AUTOMATICALLY_FLUSHABLE to host except loopback mode");
86 return;
87 }
88 if (packet_boundary_flag == PacketBoundaryFlag::CONTINUING_FRAGMENT) {
89 if (remaining_sdu_continuation_packet_size_ < payload_size) {
90 LOG_WARN("Remote sent unexpected L2CAP PDU. Drop the entire L2CAP PDU");
91 recombination_stage_ =
92 PacketViewForRecombination(PacketView<kLittleEndian>(std::make_shared<std::vector<uint8_t>>()));
93 remaining_sdu_continuation_packet_size_ = 0;
94 return;
95 }
96 remaining_sdu_continuation_packet_size_ -= payload_size;
97 recombination_stage_.AppendPacketView(payload);
98 if (remaining_sdu_continuation_packet_size_ != 0) {
99 return;
100 } else {
101 payload = recombination_stage_;
102 recombination_stage_ =
103 PacketViewForRecombination(PacketView<kLittleEndian>(std::make_shared<std::vector<uint8_t>>()));
104 }
105 } else if (packet_boundary_flag == PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE) {
106 if (recombination_stage_.size() > 0) {
107 LOG_ERROR("Controller sent a starting packet without finishing previous packet. Drop previous one.");
108 }
109 auto l2cap_pdu_size = GetL2capPduSize(packet);
110 remaining_sdu_continuation_packet_size_ = l2cap_pdu_size - (payload_size - kL2capBasicFrameHeaderSize);
111 if (remaining_sdu_continuation_packet_size_ > 0) {
112 recombination_stage_ = payload;
113 return;
114 }
115 }
116 if (incoming_queue_.size() > kMaxQueuedPacketsPerConnection) {
117 LOG_ERROR("Dropping packet from %s due to congestion", address_with_type_.ToString().c_str());
118 return;
119 }
120
121 incoming_queue_.push(payload);
122 if (!enqueue_registered_->exchange(true)) {
123 down_end_->RegisterEnqueue(handler_,
124 common::Bind(&assembler::on_le_incoming_data_ready, common::Unretained(this)));
125 }
126 }
127 };
128
129 } // namespace acl_manager
130 } // namespace hci
131 } // namespace bluetooth
132