blob: dae67e12515729c42b2a819c48677b100a398383 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/l2cap/bredr_command_handler.h"
#include <endian.h>
#include <type_traits>
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/common/byte_buffer.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/common/log.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/common/packet_view.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/l2cap/channel_configuration.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/l2cap/l2cap_defs.h"
namespace bt::l2cap::internal {
bool BrEdrCommandHandler::ConnectionResponse::Decode(
const ByteBuffer& payload_buf) {
auto conn_rsp_payload = payload_buf.To<PayloadT>();
remote_cid_ = le16toh(conn_rsp_payload.dst_cid);
local_cid_ = le16toh(conn_rsp_payload.src_cid);
result_ = static_cast<ConnectionResult>(
le16toh(static_cast<uint16_t>(conn_rsp_payload.result)));
conn_status_ = static_cast<ConnectionStatus>(
le16toh(static_cast<uint16_t>(conn_rsp_payload.status)));
return true;
}
bool BrEdrCommandHandler::ConfigurationResponse::Decode(
const ByteBuffer& payload_buf) {
PacketView<PayloadT> config_rsp(&payload_buf,
payload_buf.size() - sizeof(PayloadT));
local_cid_ = le16toh(config_rsp.header().src_cid);
flags_ = le16toh(config_rsp.header().flags);
result_ = static_cast<ConfigurationResult>(
le16toh(static_cast<uint16_t>(config_rsp.header().result)));
if (!config_.ReadOptions(config_rsp.payload_data())) {
bt_log(WARN,
"l2cap",
"could not decode channel configuration response option");
return false;
}
return true;
}
bool BrEdrCommandHandler::InformationResponse::Decode(
const ByteBuffer& payload_buf) {
PacketView<InformationResponsePayload> info_rsp(
&payload_buf, payload_buf.size() - sizeof(InformationResponsePayload));
type_ =
InformationType{le16toh(static_cast<uint16_t>(info_rsp.header().type))};
result_ = InformationResult{
le16toh(static_cast<uint16_t>(info_rsp.header().result))};
if (result_ != InformationResult::kSuccess) {
return true;
}
size_t expected_size = 0;
switch (type_) {
case InformationType::kConnectionlessMTU:
expected_size = sizeof(uint16_t);
break;
case InformationType::kExtendedFeaturesSupported:
expected_size = sizeof(ExtendedFeatures);
break;
case InformationType::kFixedChannelsSupported:
expected_size = sizeof(FixedChannelsSupported);
break;
default:
bt_log(DEBUG,
"l2cap-bredr",
"cmd: passing Information Response with unknown type %#.4hx with "
"%zu data bytes",
static_cast<unsigned short>(type_),
info_rsp.payload_size());
}
if (info_rsp.payload_size() < expected_size) {
bt_log(DEBUG,
"l2cap-bredr",
"cmd: ignoring malformed Information Response, type %#.4hx with %zu "
"data bytes",
static_cast<unsigned short>(type_),
info_rsp.payload_size());
return false;
}
data_ = info_rsp.payload_data();
return true;
}
BrEdrCommandHandler::ConnectionResponder::ConnectionResponder(
SignalingChannel::Responder* sig_responder, ChannelId remote_cid)
: Responder(sig_responder, kInvalidChannelId, remote_cid) {}
void BrEdrCommandHandler::ConnectionResponder::Send(ChannelId local_cid,
ConnectionResult result,
ConnectionStatus status) {
ConnectionResponsePayload conn_rsp = {
htole16(local_cid),
htole16(remote_cid()),
static_cast<ConnectionResult>(htole16(static_cast<uint16_t>(result))),
static_cast<ConnectionStatus>(htole16(static_cast<uint16_t>(status)))};
sig_responder_->Send(BufferView(&conn_rsp, sizeof(conn_rsp)));
}
BrEdrCommandHandler::ConfigurationResponder::ConfigurationResponder(
SignalingChannel::Responder* sig_responder, ChannelId local_cid)
: Responder(sig_responder, local_cid) {}
void BrEdrCommandHandler::ConfigurationResponder::Send(
ChannelId remote_cid,
uint16_t flags,
ConfigurationResult result,
ChannelConfiguration::ConfigurationOptions options) {
size_t options_size = 0;
for (auto& option : options) {
options_size += option->size();
}
DynamicByteBuffer config_rsp_buf(sizeof(ConfigurationResponsePayload) +
options_size);
MutablePacketView<ConfigurationResponsePayload> config_rsp(&config_rsp_buf,
options_size);
config_rsp.mutable_header()->src_cid = htole16(remote_cid);
config_rsp.mutable_header()->flags = htole16(flags);
config_rsp.mutable_header()->result =
static_cast<ConfigurationResult>(htole16(static_cast<uint16_t>(result)));
auto payload_view = config_rsp.mutable_payload_data().mutable_view();
for (auto& option : options) {
auto encoded = option->Encode();
payload_view.Write(encoded.data(), encoded.size());
payload_view = payload_view.mutable_view(encoded.size());
}
sig_responder_->Send(config_rsp.data());
}
BrEdrCommandHandler::DisconnectionResponder::DisconnectionResponder(
SignalingChannel::Responder* sig_responder,
ChannelId local_cid,
ChannelId remote_cid)
: Responder(sig_responder, local_cid, remote_cid) {}
void BrEdrCommandHandler::DisconnectionResponder::Send() {
DisconnectionResponsePayload discon_rsp = {htole16(local_cid()),
htole16(remote_cid())};
sig_responder_->Send(BufferView(&discon_rsp, sizeof(discon_rsp)));
}
BrEdrCommandHandler::InformationResponder::InformationResponder(
SignalingChannel::Responder* sig_responder, InformationType type)
: Responder(sig_responder), type_(type) {}
void BrEdrCommandHandler::InformationResponder::SendNotSupported() {
Send(InformationResult::kNotSupported, BufferView());
}
void BrEdrCommandHandler::InformationResponder::SendConnectionlessMtu(
uint16_t mtu) {
mtu = htole16(mtu);
Send(InformationResult::kSuccess, BufferView(&mtu, sizeof(mtu)));
}
void BrEdrCommandHandler::InformationResponder::SendExtendedFeaturesSupported(
ExtendedFeatures extended_features) {
extended_features = htole32(extended_features);
Send(InformationResult::kSuccess,
BufferView(&extended_features, sizeof(extended_features)));
}
void BrEdrCommandHandler::InformationResponder::SendFixedChannelsSupported(
FixedChannelsSupported channels_supported) {
channels_supported = htole64(channels_supported);
Send(InformationResult::kSuccess,
BufferView(&channels_supported, sizeof(channels_supported)));
}
void BrEdrCommandHandler::InformationResponder::Send(InformationResult result,
const ByteBuffer& data) {
constexpr size_t kMaxPayloadLength =
sizeof(InformationResponsePayload) + sizeof(uint64_t);
StaticByteBuffer<kMaxPayloadLength> info_rsp_buf;
MutablePacketView<InformationResponsePayload> info_rsp_view(&info_rsp_buf,
data.size());
info_rsp_view.mutable_header()->type =
static_cast<InformationType>(htole16(static_cast<uint16_t>(type_)));
info_rsp_view.mutable_header()->result =
static_cast<InformationResult>(htole16(static_cast<uint16_t>(result)));
info_rsp_view.mutable_payload_data().Write(data);
sig_responder_->Send(info_rsp_view.data());
}
BrEdrCommandHandler::BrEdrCommandHandler(SignalingChannelInterface* sig,
fit::closure request_fail_callback)
: CommandHandler(sig, std::move(request_fail_callback)) {}
bool BrEdrCommandHandler::SendConnectionRequest(uint16_t psm,
ChannelId local_cid,
ConnectionResponseCallback cb) {
auto on_conn_rsp = BuildResponseHandler<ConnectionResponse>(std::move(cb));
ConnectionRequestPayload payload = {htole16(psm), htole16(local_cid)};
return sig()->SendRequest(kConnectionRequest,
BufferView(&payload, sizeof(payload)),
std::move(on_conn_rsp));
}
bool BrEdrCommandHandler::SendConfigurationRequest(
ChannelId remote_cid,
uint16_t flags,
ChannelConfiguration::ConfigurationOptions options,
ConfigurationResponseCallback cb) {
auto on_config_rsp =
BuildResponseHandler<ConfigurationResponse>(std::move(cb));
size_t options_size = 0;
for (auto& option : options) {
options_size += option->size();
}
DynamicByteBuffer config_req_buf(sizeof(ConfigurationRequestPayload) +
options_size);
MutablePacketView<ConfigurationRequestPayload> config_req(&config_req_buf,
options_size);
config_req.mutable_header()->dst_cid = htole16(remote_cid);
config_req.mutable_header()->flags = htole16(flags);
auto payload_view = config_req.mutable_payload_data().mutable_view();
for (auto& option : options) {
auto encoded = option->Encode();
payload_view.Write(encoded.data(), encoded.size());
payload_view = payload_view.mutable_view(encoded.size());
}
return sig()->SendRequest(
kConfigurationRequest, config_req_buf, std::move(on_config_rsp));
}
bool BrEdrCommandHandler::SendInformationRequest(
InformationType type, InformationResponseCallback cb) {
auto on_info_rsp = BuildResponseHandler<InformationResponse>(std::move(cb));
InformationRequestPayload payload = {
InformationType{htole16(static_cast<uint16_t>(type))}};
return sig()->SendRequest(kInformationRequest,
BufferView(&payload, sizeof(payload)),
std::move(on_info_rsp));
}
void BrEdrCommandHandler::ServeConnectionRequest(ConnectionRequestCallback cb) {
auto on_conn_req = [cb = std::move(cb)](
const ByteBuffer& request_payload,
SignalingChannel::Responder* sig_responder) {
if (request_payload.size() != sizeof(ConnectionRequestPayload)) {
bt_log(DEBUG,
"l2cap-bredr",
"cmd: rejecting malformed Connection Request, size %zu",
request_payload.size());
sig_responder->RejectNotUnderstood();
return;
}
const auto& conn_req = request_payload.To<ConnectionRequestPayload>();
const Psm psm = le16toh(conn_req.psm);
const ChannelId remote_cid = le16toh(conn_req.src_cid);
ConnectionResponder responder(sig_responder, remote_cid);
// v5.0 Vol 3, Part A, Sec 4.2: PSMs shall be odd and the least significant
// bit of the most significant byte shall be zero
if (((psm & 0x0001) != 0x0001) || ((psm & 0x0100) != 0x0000)) {
bt_log(DEBUG,
"l2cap-bredr",
"Rejecting connection for invalid PSM %#.4x from channel %#.4x",
psm,
remote_cid);
responder.Send(kInvalidChannelId,
ConnectionResult::kPsmNotSupported,
ConnectionStatus::kNoInfoAvailable);
return;
}
// Check that source channel ID is in range (v5.0 Vol 3, Part A, Sec 2.1)
if (remote_cid < kFirstDynamicChannelId) {
bt_log(DEBUG,
"l2cap-bredr",
"Rejecting connection for PSM %#.4x from invalid channel %#.4x",
psm,
remote_cid);
responder.Send(kInvalidChannelId,
ConnectionResult::kInvalidSourceCID,
ConnectionStatus::kNoInfoAvailable);
return;
}
cb(psm, remote_cid, &responder);
};
sig()->ServeRequest(kConnectionRequest, std::move(on_conn_req));
}
void BrEdrCommandHandler::ServeConfigurationRequest(
ConfigurationRequestCallback cb) {
auto on_config_req = [cb = std::move(cb)](
const ByteBuffer& request_payload,
SignalingChannel::Responder* sig_responder) {
if (request_payload.size() < sizeof(ConfigurationRequestPayload)) {
bt_log(DEBUG,
"l2cap-bredr",
"cmd: rejecting malformed Configuration Request, size %zu",
request_payload.size());
sig_responder->RejectNotUnderstood();
return;
}
PacketView<ConfigurationRequestPayload> config_req(
&request_payload,
request_payload.size() - sizeof(ConfigurationRequestPayload));
const auto local_cid =
static_cast<ChannelId>(le16toh(config_req.header().dst_cid));
const uint16_t flags = le16toh(config_req.header().flags);
ConfigurationResponder responder(sig_responder, local_cid);
ChannelConfiguration config;
if (!config.ReadOptions(config_req.payload_data())) {
bt_log(WARN,
"l2cap",
"could not decode configuration option in configuration request");
}
cb(local_cid, flags, std::move(config), &responder);
};
sig()->ServeRequest(kConfigurationRequest, std::move(on_config_req));
}
void BrEdrCommandHandler::ServeInformationRequest(
InformationRequestCallback cb) {
auto on_info_req = [cb = std::move(cb)](
const ByteBuffer& request_payload,
SignalingChannel::Responder* sig_responder) {
if (request_payload.size() != sizeof(InformationRequestPayload)) {
bt_log(DEBUG,
"l2cap-bredr",
"cmd: rejecting malformed Information Request, size %zu",
request_payload.size());
sig_responder->RejectNotUnderstood();
return;
}
const auto& info_req = request_payload.To<InformationRequestPayload>();
const auto type = static_cast<InformationType>(
le16toh(static_cast<uint16_t>(info_req.type)));
InformationResponder responder(sig_responder, type);
cb(type, &responder);
};
sig()->ServeRequest(kInformationRequest, std::move(on_info_req));
}
} // namespace bt::l2cap::internal