blob: b6d14552adced652c332420dd1a0790327cd5b1f [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_SM_BEARER_H_
#define GARNET_DRIVERS_BLUETOOTH_LIB_SM_BEARER_H_
#include <lib/async/cpp/task.h>
#include <lib/fit/function.h>
#include "garnet/drivers/bluetooth/lib/common/device_address.h"
#include "garnet/drivers/bluetooth/lib/hci/connection.h"
#include "garnet/drivers/bluetooth/lib/l2cap/channel.h"
#include "garnet/drivers/bluetooth/lib/l2cap/scoped_channel.h"
#include "garnet/drivers/bluetooth/lib/l2cap/sdu.h"
#include "garnet/drivers/bluetooth/lib/sm/packet.h"
#include "garnet/drivers/bluetooth/lib/sm/smp.h"
#include "garnet/drivers/bluetooth/lib/sm/status.h"
#include "garnet/drivers/bluetooth/lib/sm/types.h"
#include "lib/fxl/macros.h"
#include "lib/fxl/memory/weak_ptr.h"
namespace btlib {
namespace sm {
// Represents the SMP data bearer operating over the fixed SMP L2CAP channel.
// Bearer encapsulates the pairing algorithms described in Vol 3, Part H, 2.3.5
// as distinct sub-procedures that are expected to be driven externally. The
// client is responsible for initiating the right sub-procedure at the right
// time.
//
// A SMP bearer can be instantiated over both LE and BR/EDR transports.
//
// THREAD SAFETY
//
// This class is not thread safe and is meant to be accessed on the thread it
// was created on. All callbacks will be run by the default dispatcher of a
// Bearer's creation thread.
class Bearer final {
public:
// Interface for receiving SMP events.
class Listener {
public:
virtual ~Listener() = default;
// Called when an on-going pairing procedure terminates with an error.
// |status| will never indicate success.
virtual void OnPairingFailed(Status status) = 0;
// Called when pairing features have been exchanged as a result of the
// "Pairing Feature Exchange" sub-procedure during Phase 1. This can be
// called when pairing is either remote or locally initated, with the
// following parameters:
// - |features|: The negotiated features.
// - |preq| and |pres|: The SMP "Pairing Request" and "Pairing Response"
// command payloads that have been exchanged between the devices. These
// values are used to generate "Mconfirm" and "Sconfirm" values used in
// LE Legacy Pairing Phase 2 (see Vol 3, Part H, 2.3.5.5). These values
// should be ignored if |secure_connections| is true.
//
// When the local device is the master, the feature exchange is either
// initiated directly via InitiateFeatureExchange() or automatically as a
// response to a "Security Request" received from the slave.
//
// When the local device is the slave, the feature exchange is initiated by
// the master or locally by calling SecurityRequest().
//
// TODO(armansito): Support locally initiated "Security Request".
//
// The Pairing Feature Exchange procedures will fail if no feature exchange
// callback is assigned.
virtual void OnFeatureExchange(const PairingFeatures& features,
const common::ByteBuffer& preq,
const common::ByteBuffer& pres) = 0;
// Called when a "confirm value" is received from the peer during Legacy
// Pairing Phase 2.
virtual void OnPairingConfirm(const common::UInt128& confirm) = 0;
// Called when a "random value" is received from the peer during Legacy
// Pairing Phase 2.
virtual void OnPairingRandom(const common::UInt128& random) = 0;
// Called when a "Long Term Key" is received from the peer.
virtual void OnLongTermKey(const common::UInt128& ltk) = 0;
// Called when EDiv and Rand values are received from the peer during Legacy
// Pairing Phase 3.
virtual void OnMasterIdentification(uint16_t ediv, uint64_t random) = 0;
// Called when the "Identity Resolving Key" is received from the peer during
// Phase 3.
virtual void OnIdentityResolvingKey(const common::UInt128& irk) = 0;
// Called when the "Identity Address" is received from the peer during Phase
// 3.
virtual void OnIdentityAddress(const common::DeviceAddress& address) = 0;
};
// Initializes this Bearer with the following parameters:
// - |chan|: The L2CAP SMP fixed channel.
// - |role|: The local connection role.
// - |secure_connections_supported|: True if the local device supports LE
// Secure Connections pairing.
// - |io_capability|: The local I/O capability.
Bearer(fbl::RefPtr<l2cap::Channel> chan, hci::Connection::Role role,
bool secure_connections_supported, IOCapability io_capability,
fxl::WeakPtr<Listener> listener);
~Bearer() = default;
// Sets new I/O capabilities. These will be used in future pairing feature
// exchanges.
void set_io_capability(IOCapability ioc) { io_capability_ = ioc; }
// Sets whether or not OOB authentication data is available. False by default.
void set_oob_available(bool value) { oob_available_ = value; }
// Sets whether MITM protection is required. False by default.
void set_mitm_required(bool value) { mitm_required_ = value; }
// Returns true if pairing has been initiated.
bool pairing_started() const { return timeout_task_.is_pending(); }
// Returns the connection role.
hci::Connection::Role role() const { return role_; }
// Initiates "Pairing Feature Exchange" with the local device as the
// initiator (Vol 3, Part H, 2.3). A successful exchange will be indicated by
// calling via feature exchange callback and failure via the error callback.
//
// Returns false if the procedure cannot be initiated because:
// - This procedure is already in progress.
// - The local device is the slave in the connection.
//
// This method can be called on both LE and BR/EDR.
bool InitiateFeatureExchange();
// Sends a "confirm value" for Phase 2 of legacy pairing. Returns false if
// feature exchange is in progress or pairing hasn't been started.
bool SendConfirmValue(const common::UInt128& confirm);
// Sends a "random value" for Phase 2 of legacy pairing. Returns false if
// feature exchange is in progress or pairing hasn't been started.
bool SendRandomValue(const common::UInt128& random);
// Sends the encryption information during the key distribution phase
// (Phase 3) of legacy pairing. Returns false if the command cannot be sent.
bool SendEncryptionKey(const hci::LinkKey& link_key);
// Stops the pairing timer. The pairing timer is started when a Pairing
// Request or Security Request is sent or received and must be explicitly
// stopped once all required keys have been distributed.
//
// A L2CAP link error will be signaled if the timer expires within
// kPairingTimeout seconds (see smp.h).
void StopTimer();
// Ends the current pairing procedure with the given failure |ecode|.
void Abort(ErrorCode ecode);
private:
// Cleans up all pairing state and and invokes the error calback.
void OnFailure(Status status);
// Called when the SMP pairing timer expires.
void OnPairingTimeout();
// Called to complete a feature exchange. Returns ErrorCode::kNoError if the
// parameters should be accepted and returns the final values in
// |out_features|. Returns an error code if the parameters have been rejected
// and pairing should be aborted.
ErrorCode ResolveFeatures(bool local_initiator,
const PairingRequestParams& preq,
const PairingResponseParams& pres,
PairingFeatures* out_features);
// Populates a pairing request/response structure based on features that we
// support and request. Used to build a SMP PairingRequest and PairingResponse
// PDU during feature exchange.
//
// This does not populate the initiator/responder key distribution and
// generation fields of |params|. Instead the requested remote and local keys
// are provided in |out_local_keys| and |out_remote_keys|. The caller is
// responsible for calculating the appropriate dist/gen values that are
// suitable for |params| depending on context.
void BuildPairingParameters(PairingRequestParams* params,
KeyDistGenField* out_local_keys,
KeyDistGenField* out_remote_keys);
// Called for SMP commands that are sent by the peer.
void OnPairingFailed(const PacketReader& reader);
void OnPairingRequest(const PacketReader& reader);
void OnPairingResponse(const PacketReader& reader);
void OnPairingConfirm(const PacketReader& reader);
void OnPairingRandom(const PacketReader& reader);
void OnEncryptionInformation(const PacketReader& reader);
void OnMasterIdentification(const PacketReader& reader);
void OnIdentityInformation(const PacketReader& reader);
void OnIdentityAddressInformation(const PacketReader& reader);
// Sends a Pairing Failed command to the peer.
void SendPairingFailed(ErrorCode ecode);
// l2cap::Channel callbacks:
void OnChannelClosed();
void OnRxBFrame(const l2cap::SDU& sdu);
l2cap::ScopedChannel chan_;
hci::Connection::Role role_;
bool oob_available_;
bool mitm_required_;
bool sc_supported_;
IOCapability io_capability_;
fxl::WeakPtr<Listener> listener_;
uint8_t mtu_;
// We use this buffer to store pairing request and response PDUs as they are
// needed to complete the feature exchange (i.e. the "preq" and "pres"
// payloads needed for Phase 2 (see Vol 3, Part H, 2.2.3 for example).
common::StaticByteBuffer<sizeof(Header) + sizeof(PairingRequestParams)>
pairing_payload_buffer_;
// Task used to drive the "SMP Timeout" (Vol 3, Part H, 3.4). The timer is
// started when pairing is initiated.
async::TaskClosureMethod<Bearer, &Bearer::OnPairingTimeout> timeout_task_{
this};
// True if a pairing feature exchange has been initiated and waiting for a
// response.
bool feature_exchange_pending_;
fxl::WeakPtrFactory<Bearer> weak_ptr_factory_;
FXL_DISALLOW_COPY_AND_ASSIGN(Bearer);
};
} // namespace sm
} // namespace btlib
#endif // GARNET_DRIVERS_BLUETOOTH_LIB_SM_BEARER_H_