blob: 875aaab14d6a9b9e07d6a2bc215b171ce9b88d61 [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.
#ifndef SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_L2CAP_BREDR_COMMAND_HANDLER_H_
#define SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_L2CAP_BREDR_COMMAND_HANDLER_H_
#include <lib/fit/function.h>
#include <memory>
#include "src/connectivity/bluetooth/core/bt-host/common/byte_buffer.h"
#include "src/connectivity/bluetooth/core/bt-host/l2cap/channel_configuration.h"
#include "src/connectivity/bluetooth/core/bt-host/l2cap/command_handler.h"
#include "src/connectivity/bluetooth/core/bt-host/l2cap/l2cap_defs.h"
#include "src/connectivity/bluetooth/core/bt-host/l2cap/signaling_channel.h"
namespace bt::l2cap::internal {
// Wrapper for a BR/EDR signaling channel that sends and receives command
// transactions.
class BrEdrCommandHandler final : public CommandHandler {
public:
class ConnectionResponse final : public Response {
public:
using PayloadT = ConnectionResponsePayload;
static constexpr const char* kName = "Connection Response";
using Response::Response; // Inherit ctor
bool Decode(const ByteBuffer& payload_buf);
ConnectionResult result() const { return result_; }
ConnectionStatus conn_status() const { return conn_status_; }
private:
ConnectionResult result_;
ConnectionStatus conn_status_;
};
class ConfigurationResponse final : public Response {
public:
using PayloadT = ConfigurationResponsePayload;
static constexpr const char* kName = "Configuration Response";
using Response::Response; // Inherit ctor
bool Decode(const ByteBuffer& payload_buf);
uint16_t flags() const { return flags_; }
ConfigurationResult result() const { return result_; }
const ChannelConfiguration& config() const { return config_; }
private:
friend class BrEdrCommandHandler;
uint16_t flags_;
ConfigurationResult result_;
ChannelConfiguration config_;
};
class InformationResponse final : public Response {
public:
using PayloadT = InformationResponsePayload;
static constexpr const char* kName = "Information Response";
using Response::Response; // Inherit ctor
bool Decode(const ByteBuffer& payload_buf);
InformationType type() const { return type_; }
InformationResult result() const { return result_; }
uint16_t connectionless_mtu() const {
ZX_ASSERT(result() == InformationResult::kSuccess);
ZX_ASSERT(type() == InformationType::kConnectionlessMTU);
return data_.As<uint16_t>();
}
ExtendedFeatures extended_features() const {
ZX_ASSERT(result() == InformationResult::kSuccess);
ZX_ASSERT(type() == InformationType::kExtendedFeaturesSupported);
return data_.As<ExtendedFeatures>();
}
FixedChannelsSupported fixed_channels() const {
ZX_ASSERT(result() == InformationResult::kSuccess);
ZX_ASSERT(type() == InformationType::kFixedChannelsSupported);
return data_.As<FixedChannelsSupported>();
}
private:
friend class BrEdrCommandHandler;
InformationType type_;
InformationResult result_;
// View into the payload received from the peer in host endianness. It is
// only valid for the duration of the InformationResponseCallback
// invocation.
BufferView data_;
};
using ConnectionResponseCallback = fit::function<SignalingChannelInterface::ResponseHandlerAction(
const ConnectionResponse& rsp)>;
using ConfigurationResponseCallback =
fit::function<ResponseHandlerAction(const ConfigurationResponse& rsp)>;
// Information Responses never have additional responses.
using InformationResponseCallback = fit::function<void(const InformationResponse& rsp)>;
class ConnectionResponder final : public Responder {
public:
ConnectionResponder(SignalingChannel::Responder* sig_responder, ChannelId remote_cid);
void Send(ChannelId local_cid, ConnectionResult result, ConnectionStatus status);
};
class ConfigurationResponder final : public Responder {
public:
ConfigurationResponder(SignalingChannel::Responder* sig_responder, ChannelId local_cid);
void Send(ChannelId remote_cid, uint16_t flags, ConfigurationResult result,
ChannelConfiguration::ConfigurationOptions options);
};
class InformationResponder final : public Responder {
public:
InformationResponder(SignalingChannel::Responder* sig_responder, InformationType type);
void SendNotSupported();
void SendConnectionlessMtu(uint16_t mtu);
void SendExtendedFeaturesSupported(ExtendedFeatures extended_features);
void SendFixedChannelsSupported(FixedChannelsSupported channels_supported);
private:
void Send(InformationResult result, const ByteBuffer& data);
InformationType type_;
};
using ConnectionRequestCallback =
fit::function<void(PSM psm, ChannelId remote_cid, ConnectionResponder* responder)>;
using ConfigurationRequestCallback =
fit::function<void(ChannelId local_cid, uint16_t flags, ChannelConfiguration config,
ConfigurationResponder* responder)>;
using InformationRequestCallback =
fit::function<void(InformationType type, InformationResponder* responder)>;
// |sig| must be valid for the lifetime of this object.
// |command_failed_callback| is called if an outbound request timed out with
// RTX or ERTX timers after retransmission (if configured). The call may come
// after the lifetime of this object.
explicit BrEdrCommandHandler(SignalingChannelInterface* sig,
fit::closure request_fail_callback = nullptr);
~BrEdrCommandHandler() = default;
// Disallow copy even though there's no state because having multiple
// BrEdrCommandHandlers in the same scope is likely due to a bug or is at
// least redundant.
DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(BrEdrCommandHandler);
// Outbound request sending methods. Response callbacks are required to be
// non-empty. The callbacks are wrapped and moved into the SignalingChannel
// and may outlive BrEdrCommandHandler.
bool SendConnectionRequest(uint16_t psm, ChannelId local_cid, ConnectionResponseCallback cb);
bool SendConfigurationRequest(ChannelId remote_cid, uint16_t flags,
ChannelConfiguration::ConfigurationOptions options,
ConfigurationResponseCallback cb);
bool SendInformationRequest(InformationType type, InformationResponseCallback cb);
// Inbound request delegate registration methods. The callbacks are wrapped
// and moved into the SignalingChannel and may outlive BrEdrCommandHandler. It
// is expected that any request delegates registered will span the lifetime of
// its signaling channel and hence link, so no unregistration is provided.
// However each call to register will replace any currently registered request
// delegate.
void ServeConnectionRequest(ConnectionRequestCallback cb);
void ServeConfigurationRequest(ConfigurationRequestCallback cb);
void ServeInformationRequest(InformationRequestCallback cb);
};
} // namespace bt::l2cap::internal
#endif // SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_L2CAP_BREDR_COMMAND_HANDLER_H_