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