blob: 8f78f47a52d195b076ed9f2a1a1861539f86dafc [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 GARNET_DRIVERS_BLUETOOTH_LIB_L2CAP_BREDR_DYNAMIC_CHANNEL_H_
#define GARNET_DRIVERS_BLUETOOTH_LIB_L2CAP_BREDR_DYNAMIC_CHANNEL_H_
#include <unordered_map>
#include <lib/fit/function.h>
#include "garnet/drivers/bluetooth/lib/l2cap/bredr_command_handler.h"
#include "garnet/drivers/bluetooth/lib/l2cap/dynamic_channel_registry.h"
#include "garnet/drivers/bluetooth/lib/l2cap/l2cap.h"
#include "garnet/drivers/bluetooth/lib/l2cap/signaling_channel.h"
namespace btlib {
namespace l2cap {
namespace internal {
// Implements factories for BR/EDR dynamic channels and dispatches incoming
// signaling channel requests to the corresponding channels by local ID.
//
// Must be run only on the L2CAP thread.
class BrEdrDynamicChannelRegistry final : public DynamicChannelRegistry {
public:
BrEdrDynamicChannelRegistry(SignalingChannelInterface* sig,
DynamicChannelCallback close_cb,
ServiceRequestCallback service_request_cb);
~BrEdrDynamicChannelRegistry() override = default;
private:
// DynamicChannelRegistry override
DynamicChannelPtr MakeOutbound(PSM psm, ChannelId local_cid) override;
DynamicChannelPtr MakeInbound(PSM psm, ChannelId local_cid,
ChannelId remote_cid) override;
// Signaling channel request handlers
void OnRxConnReq(PSM psm, ChannelId remote_cid,
BrEdrCommandHandler::ConnectionResponder* responder);
void OnRxConfigReq(ChannelId local_cid, uint16_t flags,
const common::ByteBuffer& options,
BrEdrCommandHandler::ConfigurationResponder* responder);
void OnRxDisconReq(ChannelId local_cid, ChannelId remote_cid,
BrEdrCommandHandler::DisconnectionResponder* responder);
void OnRxInfoReq(InformationType type,
BrEdrCommandHandler::InformationResponder* responder);
SignalingChannelInterface* const sig_;
};
class BrEdrDynamicChannel;
using BrEdrDynamicChannelPtr = std::unique_ptr<BrEdrDynamicChannel>;
// Creates, configures, and tears down dynamic channels using the BR/EDR
// signaling channel. The lifetime of this object matches that of the channel
// itself: created in order to start an outbound channel or in response to an
// inbound channel request, then destroyed immediately after the channel is
// closed. This is intended to be created and owned by
// BrEdrDynamicChannelRegistry.
//
// This implements the state machine described by v5.0 Vol 3 Part A Sec 6. The
// state of OPEN ("user data transfer state") matches the implementation of the
// |DynamicChannel::IsOpen()|.
//
// Must be run only on the L2CAP thread.
class BrEdrDynamicChannel final : public DynamicChannel {
public:
static BrEdrDynamicChannelPtr MakeOutbound(
DynamicChannelRegistry* registry,
SignalingChannelInterface* signaling_channel, PSM psm,
ChannelId local_cid);
static BrEdrDynamicChannelPtr MakeInbound(
DynamicChannelRegistry* registry,
SignalingChannelInterface* signaling_channel, PSM psm,
ChannelId local_cid, ChannelId remote_cid);
// DynamicChannel overrides
~BrEdrDynamicChannel() override = default;
void Open(fit::closure open_cb) override;
// Mark this channel as closed and disconnected. Send a Disconnection Request
// to the remote peer if possible (remote peer had send an ID for its
// endpoint). This object shall be destroyed after this call returns and it is
// safe to do so regardless of receiving the Disconnection Response.
void Disconnect() override;
bool IsConnected() const override;
bool IsOpen() const override;
// Inbound request handlers. Request must have a destination channel ID that
// matches this instance's |local_cid|.
void OnRxConfigReq(uint16_t flags, const common::ByteBuffer& options,
BrEdrCommandHandler::ConfigurationResponder* responder);
void OnRxDisconReq(BrEdrCommandHandler::DisconnectionResponder* responder);
// Reply with affirmative connection response and begin configuration.
void CompleteInboundConnection(
BrEdrCommandHandler::ConnectionResponder* responder);
private:
// The channel configuration state is described in v5.0 Vol 3 Part A Sec 6 (in
// particular in Fig. 6.2) as having numerous substates in order to capture
// the different orders in which configuration packets may be transmitted. It
// is implemented here as a bitfield where bits are set as each packet is
// transmitted.
//
// The initial state for a channel prior to any signaling packets transmitted
// is 0.
using State = uint8_t;
enum StateBit : State {
// Connection Req (transmitted in either direction)
kConnRequested = (1 << 0),
// Connection Rsp (transmitted in opposite direction of Connection Req)
kConnResponded = (1 << 1),
// Configuration Req (transmitted from local to remote)
kLocalConfigSent = (1 << 2),
// Configuration Rsp (successful; transmitted from remote to local)
kLocalConfigAccepted = (1 << 3),
// Configuration Req (transmitted from remote to local)
kRemoteConfigReceived = (1 << 4),
// Configuration Rsp (successful; transmitted from local to remote)
kRemoteConfigAccepted = (1 << 5),
// Disconnection Req (transmitted in either direction)
kDisconnected = (1 << 6),
};
// TODO(NET-1319): Add Extended Flow Specification steps (exchange &
// controller configuration)
BrEdrDynamicChannel(DynamicChannelRegistry* registry,
SignalingChannelInterface* signaling_channel, PSM psm,
ChannelId local_cid, ChannelId remote_cid);
// Deliver the result of channel connection and configuration to the |Open|
// originator. Can be called multiple times but only the first invocation
// passes the result.
void PassOpenResult();
// Error during channel connection or configuration (before it is open).
// Deliver the error open result to the |Open| originator. Disconnect the
// remote endpoint of the channel if possible. If the channel is already open,
// use |Disconnect| instead.
void PassOpenError();
// Begin the local channel Configuration Request flow if it has not yet
// happened.
void TrySendLocalConfig();
// Response handlers for outbound requests
bool OnRxConnRsp(const BrEdrCommandHandler::ConnectionResponse& rsp);
bool OnRxConfigRsp(const BrEdrCommandHandler::ConfigurationResponse& rsp);
SignalingChannelInterface* const signaling_channel_;
// Bit field assembled using the bit masks above. When zero, it represents a
// closed (i.e. not yet open) channel.
State state_;
// This shall be reset to nullptr after invocation to enforce its single-use
// semantics. See |DynamicChannel::Open| for details.
fit::closure open_result_cb_;
};
} // namespace internal
} // namespace l2cap
} // namespace btlib
#endif // GARNET_DRIVERS_BLUETOOTH_LIB_L2CAP_BREDR_DYNAMIC_CHANNEL_H_