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 #include <bluetooth/log.h>
20 
21 #include <cstddef>
22 #include <cstdint>
23 #include <memory>
24 #include <vector>
25 
26 #include "hci/acl_manager/acl_connection.h"
27 #include "hci/address_with_type.h"
28 #include "os/handler.h"
29 #include "packet/packet_view.h"
30 
31 namespace bluetooth {
32 namespace hci {
33 namespace acl_manager {
34 
35 constexpr size_t kMaxQueuedPacketsPerConnection = 10;
36 constexpr size_t kL2capBasicFrameHeaderSize = 4;
37 
38 namespace {
39 // This is a helper class to keep the state of the assembler and expose PacketView<>::Append.
40 class PacketViewForRecombination : public packet::PacketView<packet::kLittleEndian> {
41 public:
PacketViewForRecombination(const PacketView & packetView)42   PacketViewForRecombination(const PacketView& packetView)
43       : PacketView(packetView), received_first_(true) {}
44 
PacketViewForRecombination()45   PacketViewForRecombination()
46       : PacketView(PacketView<packet::kLittleEndian>(std::make_shared<std::vector<uint8_t>>())) {}
47 
AppendPacketView(packet::PacketView<packet::kLittleEndian> to_append)48   void AppendPacketView(packet::PacketView<packet::kLittleEndian> to_append) { Append(to_append); }
49 
ReceivedFirstPacket()50   bool ReceivedFirstPacket() { return received_first_; }
51 
52 private:
53   bool received_first_{};
54 };
55 
56 // Per spec 5.1 Vol 2 Part B 5.3, ACL link shall carry L2CAP data. Therefore, an ACL packet shall
57 // contain L2CAP PDU. This function returns the PDU size of the L2CAP starting packet, or
58 // kL2capBasicFrameHeaderSize if it's invalid.
GetL2capPduSize(packet::PacketView<packet::kLittleEndian> pdu)59 size_t GetL2capPduSize(packet::PacketView<packet::kLittleEndian> pdu) {
60   if (pdu.size() < 2) {
61     return kL2capBasicFrameHeaderSize;  // We need at least 4 bytes to send it to L2CAP
62   }
63   return (static_cast<size_t>(pdu[1]) << 8u) + pdu[0];
64 }
65 
66 }  // namespace
67 
68 struct assembler {
assemblerassembler69   assembler(AddressWithType address_with_type, AclConnection::QueueDownEnd* down_end,
70             os::Handler* handler)
71       : address_with_type_(address_with_type), down_end_(down_end), handler_(handler) {}
72   AddressWithType address_with_type_;
73   AclConnection::QueueDownEnd* down_end_;
74   os::Handler* handler_;
75   PacketViewForRecombination recombination_stage_{};
76   std::shared_ptr<std::atomic_bool> enqueue_registered_ = std::make_shared<std::atomic_bool>(false);
77   std::queue<packet::PacketView<packet::kLittleEndian>> incoming_queue_;
78 
~assemblerassembler79   ~assembler() {
80     if (enqueue_registered_->exchange(false)) {
81       down_end_->UnregisterEnqueue();
82     }
83   }
84 
85   // Invoked from some external Queue Reactable context
on_data_readyassembler86   std::unique_ptr<packet::PacketView<packet::kLittleEndian>> on_data_ready() {
87     auto packet = incoming_queue_.front();
88     incoming_queue_.pop();
89     if (incoming_queue_.empty() && enqueue_registered_->exchange(false)) {
90       down_end_->UnregisterEnqueue();
91     }
92     return std::make_unique<PacketView<packet::kLittleEndian>>(packet);
93   }
94 
on_incoming_packetassembler95   void on_incoming_packet(AclView packet) {
96     PacketView<packet::kLittleEndian> payload = packet.GetPayload();
97     auto broadcast_flag = packet.GetBroadcastFlag();
98     if (broadcast_flag == BroadcastFlag::ACTIVE_PERIPHERAL_BROADCAST) {
99       log::warn("Dropping broadcast from remote");
100       return;
101     }
102     auto packet_boundary_flag = packet.GetPacketBoundaryFlag();
103     if (packet_boundary_flag == PacketBoundaryFlag::FIRST_NON_AUTOMATICALLY_FLUSHABLE) {
104       log::error(
105               "Controller is not allowed to send FIRST_NON_AUTOMATICALLY_FLUSHABLE to host except "
106               "loopback mode");
107       return;
108     }
109     if (packet_boundary_flag == PacketBoundaryFlag::CONTINUING_FRAGMENT) {
110       if (!recombination_stage_.ReceivedFirstPacket()) {
111         log::error("Continuing fragment received without previous first, dropping it.");
112         return;
113       }
114       recombination_stage_.AppendPacketView(payload);
115     } else if (packet_boundary_flag == PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE) {
116       if (recombination_stage_.ReceivedFirstPacket()) {
117         log::error(
118                 "Controller sent a starting packet without finishing previous packet. Drop "
119                 "previous "
120                 "one.");
121       }
122       recombination_stage_ = payload;
123     }
124     // Check the size of the packet
125     size_t expected_size = GetL2capPduSize(recombination_stage_) + kL2capBasicFrameHeaderSize;
126     if (expected_size < recombination_stage_.size()) {
127       log::info("Packet size doesn't match L2CAP header, dropping it.");
128       recombination_stage_ = PacketViewForRecombination();
129       return;
130     } else if (expected_size > recombination_stage_.size()) {
131       // Wait for the next fragment before sending
132       return;
133     }
134     if (incoming_queue_.size() > kMaxQueuedPacketsPerConnection) {
135       log::error("Dropping packet from {} due to congestion", address_with_type_);
136       recombination_stage_ = PacketViewForRecombination();
137       return;
138     }
139 
140     incoming_queue_.push(recombination_stage_);
141     recombination_stage_ = PacketViewForRecombination();
142     if (!enqueue_registered_->exchange(true)) {
143       down_end_->RegisterEnqueue(handler_,
144                                  common::Bind(&assembler::on_data_ready, common::Unretained(this)));
145     }
146   }
147 };
148 
149 }  // namespace acl_manager
150 }  // namespace hci
151 }  // namespace bluetooth
152