• 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 #include <cstddef>
20 #include <cstdint>
21 #include <memory>
22 
23 #include "hci/acl_manager/acl_connection.h"
24 #include "hci/address_with_type.h"
25 #include "os/handler.h"
26 #include "os/log.h"
27 #include "packet/packet_view.h"
28 
29 namespace bluetooth {
30 namespace hci {
31 namespace acl_manager {
32 
33 constexpr size_t kMaxQueuedPacketsPerConnection = 10;
34 constexpr size_t kL2capBasicFrameHeaderSize = 4;
35 
36 namespace {
37 class PacketViewForRecombination : public packet::PacketView<packet::kLittleEndian> {
38  public:
PacketViewForRecombination(const PacketView & packetView)39   PacketViewForRecombination(const PacketView& packetView) : PacketView(packetView) {}
AppendPacketView(packet::PacketView<packet::kLittleEndian> to_append)40   void AppendPacketView(packet::PacketView<packet::kLittleEndian> to_append) {
41     Append(to_append);
42   }
43 };
44 
45 // Per spec 5.1 Vol 2 Part B 5.3, ACL link shall carry L2CAP data. Therefore, an ACL packet shall contain L2CAP PDU.
46 // 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)47 uint16_t GetL2capPduSize(AclView packet) {
48   auto l2cap_payload = packet.GetPayload();
49   if (l2cap_payload.size() < kL2capBasicFrameHeaderSize) {
50     LOG_ERROR("Controller sent an invalid L2CAP starting packet!");
51     return 0;
52   }
53   return (l2cap_payload.at(1) << 8u) + l2cap_payload.at(0);
54 }
55 
56 }  // namespace
57 
58 struct assembler {
assemblerassembler59   assembler(AddressWithType address_with_type, AclConnection::QueueDownEnd* down_end, os::Handler* handler)
60       : address_with_type_(address_with_type), down_end_(down_end), handler_(handler) {}
61   AddressWithType address_with_type_;
62   AclConnection::QueueDownEnd* down_end_;
63   os::Handler* handler_;
64   PacketViewForRecombination recombination_stage_{
65       PacketView<packet::kLittleEndian>(std::make_shared<std::vector<uint8_t>>())};
66   size_t remaining_sdu_continuation_packet_size_ = 0;
67   std::shared_ptr<std::atomic_bool> enqueue_registered_ = std::make_shared<std::atomic_bool>(false);
68   std::queue<packet::PacketView<packet::kLittleEndian>> incoming_queue_;
69 
~assemblerassembler70   ~assembler() {
71     if (enqueue_registered_->exchange(false)) {
72       down_end_->UnregisterEnqueue();
73     }
74   }
75 
76   // Invoked from some external Queue Reactable context
on_le_incoming_data_readyassembler77   std::unique_ptr<packet::PacketView<packet::kLittleEndian>> on_le_incoming_data_ready() {
78     auto packet = incoming_queue_.front();
79     incoming_queue_.pop();
80     if (incoming_queue_.empty() && enqueue_registered_->exchange(false)) {
81       down_end_->UnregisterEnqueue();
82     }
83     return std::make_unique<PacketView<packet::kLittleEndian>>(packet);
84   }
85 
on_incoming_packetassembler86   void on_incoming_packet(AclView packet) {
87     PacketView<packet::kLittleEndian> payload = packet.GetPayload();
88     auto payload_size = payload.size();
89     auto broadcast_flag = packet.GetBroadcastFlag();
90     if (broadcast_flag == BroadcastFlag::ACTIVE_PERIPHERAL_BROADCAST) {
91       LOG_WARN("Dropping broadcast from remote");
92       return;
93     }
94     auto packet_boundary_flag = packet.GetPacketBoundaryFlag();
95     if (packet_boundary_flag == PacketBoundaryFlag::FIRST_NON_AUTOMATICALLY_FLUSHABLE) {
96       LOG_ERROR("Controller is not allowed to send FIRST_NON_AUTOMATICALLY_FLUSHABLE to host except loopback mode");
97       return;
98     }
99     if (packet_boundary_flag == PacketBoundaryFlag::CONTINUING_FRAGMENT) {
100       if (remaining_sdu_continuation_packet_size_ < payload_size) {
101         LOG_WARN("Remote sent unexpected L2CAP PDU. Drop the entire L2CAP PDU");
102         recombination_stage_ =
103             PacketViewForRecombination(PacketView<packet::kLittleEndian>(std::make_shared<std::vector<uint8_t>>()));
104         remaining_sdu_continuation_packet_size_ = 0;
105         return;
106       }
107       remaining_sdu_continuation_packet_size_ -= payload_size;
108       recombination_stage_.AppendPacketView(payload);
109       if (remaining_sdu_continuation_packet_size_ != 0) {
110         return;
111       } else {
112         payload = recombination_stage_;
113         recombination_stage_ =
114             PacketViewForRecombination(PacketView<packet::kLittleEndian>(std::make_shared<std::vector<uint8_t>>()));
115       }
116     } else if (packet_boundary_flag == PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE) {
117       if (recombination_stage_.size() > 0) {
118         LOG_ERROR("Controller sent a starting packet without finishing previous packet. Drop previous one.");
119       }
120       auto l2cap_pdu_size = GetL2capPduSize(packet);
121       remaining_sdu_continuation_packet_size_ = l2cap_pdu_size - (payload_size - kL2capBasicFrameHeaderSize);
122       if (remaining_sdu_continuation_packet_size_ > 0) {
123         recombination_stage_ = payload;
124         return;
125       }
126     }
127     if (incoming_queue_.size() > kMaxQueuedPacketsPerConnection) {
128       LOG_ERROR("Dropping packet from %s due to congestion", address_with_type_.ToString().c_str());
129       return;
130     }
131 
132     incoming_queue_.push(payload);
133     if (!enqueue_registered_->exchange(true)) {
134       down_end_->RegisterEnqueue(handler_,
135                                  common::Bind(&assembler::on_le_incoming_data_ready, common::Unretained(this)));
136     }
137   }
138 };
139 
140 }  // namespace acl_manager
141 }  // namespace hci
142 }  // namespace bluetooth
143