• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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