1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
|
/*
* Copyright 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <cstddef>
#include <cstdint>
#include <memory>
#include "hci/acl_manager/acl_connection.h"
#include "hci/address_with_type.h"
#include "os/handler.h"
#include "os/log.h"
#include "packet/packet_view.h"
namespace bluetooth {
namespace hci {
namespace acl_manager {
constexpr size_t kMaxQueuedPacketsPerConnection = 10;
constexpr size_t kL2capBasicFrameHeaderSize = 4;
namespace {
class PacketViewForRecombination : public packet::PacketView<packet::kLittleEndian> {
public:
PacketViewForRecombination(const PacketView& packetView) : PacketView(packetView) {}
void AppendPacketView(packet::PacketView<packet::kLittleEndian> to_append) {
Append(to_append);
}
};
// Per spec 5.1 Vol 2 Part B 5.3, ACL link shall carry L2CAP data. Therefore, an ACL packet shall contain L2CAP PDU.
// This function returns the PDU size of the L2CAP data if it's a starting packet. Returns 0 if it's invalid.
uint16_t GetL2capPduSize(AclView packet) {
auto l2cap_payload = packet.GetPayload();
if (l2cap_payload.size() < kL2capBasicFrameHeaderSize) {
LOG_ERROR("Controller sent an invalid L2CAP starting packet!");
return 0;
}
return (l2cap_payload.at(1) << 8u) + l2cap_payload.at(0);
}
} // namespace
struct assembler {
assembler(AddressWithType address_with_type, AclConnection::QueueDownEnd* down_end, os::Handler* handler)
: address_with_type_(address_with_type), down_end_(down_end), handler_(handler) {}
AddressWithType address_with_type_;
AclConnection::QueueDownEnd* down_end_;
os::Handler* handler_;
PacketViewForRecombination recombination_stage_{
PacketView<packet::kLittleEndian>(std::make_shared<std::vector<uint8_t>>())};
size_t remaining_sdu_continuation_packet_size_ = 0;
std::shared_ptr<std::atomic_bool> enqueue_registered_ = std::make_shared<std::atomic_bool>(false);
std::queue<packet::PacketView<packet::kLittleEndian>> incoming_queue_;
~assembler() {
if (enqueue_registered_->exchange(false)) {
down_end_->UnregisterEnqueue();
}
}
// Invoked from some external Queue Reactable context
std::unique_ptr<packet::PacketView<packet::kLittleEndian>> on_le_incoming_data_ready() {
auto packet = incoming_queue_.front();
incoming_queue_.pop();
if (incoming_queue_.empty() && enqueue_registered_->exchange(false)) {
down_end_->UnregisterEnqueue();
}
return std::make_unique<PacketView<packet::kLittleEndian>>(packet);
}
void on_incoming_packet(AclView packet) {
PacketView<packet::kLittleEndian> payload = packet.GetPayload();
auto payload_size = payload.size();
auto broadcast_flag = packet.GetBroadcastFlag();
if (broadcast_flag == BroadcastFlag::ACTIVE_PERIPHERAL_BROADCAST) {
LOG_WARN("Dropping broadcast from remote");
return;
}
auto packet_boundary_flag = packet.GetPacketBoundaryFlag();
if (packet_boundary_flag == PacketBoundaryFlag::FIRST_NON_AUTOMATICALLY_FLUSHABLE) {
LOG_ERROR("Controller is not allowed to send FIRST_NON_AUTOMATICALLY_FLUSHABLE to host except loopback mode");
return;
}
if (packet_boundary_flag == PacketBoundaryFlag::CONTINUING_FRAGMENT) {
if (remaining_sdu_continuation_packet_size_ < payload_size) {
LOG_WARN("Remote sent unexpected L2CAP PDU. Drop the entire L2CAP PDU");
recombination_stage_ =
PacketViewForRecombination(PacketView<packet::kLittleEndian>(std::make_shared<std::vector<uint8_t>>()));
remaining_sdu_continuation_packet_size_ = 0;
return;
}
remaining_sdu_continuation_packet_size_ -= payload_size;
recombination_stage_.AppendPacketView(payload);
if (remaining_sdu_continuation_packet_size_ != 0) {
return;
} else {
payload = recombination_stage_;
recombination_stage_ =
PacketViewForRecombination(PacketView<packet::kLittleEndian>(std::make_shared<std::vector<uint8_t>>()));
}
} else if (packet_boundary_flag == PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE) {
if (recombination_stage_.size() > 0) {
LOG_ERROR("Controller sent a starting packet without finishing previous packet. Drop previous one.");
}
auto l2cap_pdu_size = GetL2capPduSize(packet);
remaining_sdu_continuation_packet_size_ = l2cap_pdu_size - (payload_size - kL2capBasicFrameHeaderSize);
if (remaining_sdu_continuation_packet_size_ > 0) {
recombination_stage_ = payload;
return;
}
}
if (incoming_queue_.size() > kMaxQueuedPacketsPerConnection) {
LOG_ERROR("Dropping packet from %s due to congestion", address_with_type_.ToString().c_str());
return;
}
incoming_queue_.push(payload);
if (!enqueue_registered_->exchange(true)) {
down_end_->RegisterEnqueue(handler_,
common::Bind(&assembler::on_le_incoming_data_ready, common::Unretained(this)));
}
}
};
} // namespace acl_manager
} // namespace hci
} // namespace bluetooth
|