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