blob: 00778c425278a78423083fdeddf3810d7af69ecc [file] [log] [blame]
// Copyright 2020 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 <lib/async/cpp/task.h>
#include <lib/fit/function.h>
#include "src/connectivity/bluetooth/core/bt-host/hci/connection.h"
#include "src/connectivity/bluetooth/core/bt-host/l2cap/channel.h"
#include "src/connectivity/bluetooth/core/bt-host/sm/pairing_phase.h"
#include "src/connectivity/bluetooth/core/bt-host/sm/smp.h"
#include "src/connectivity/bluetooth/core/bt-host/sm/types.h"
#include "src/connectivity/bluetooth/core/bt-host/sm/util.h"
#include "src/lib/fxl/memory/weak_ptr.h"
namespace bt {
namespace sm {
// Responsible for Phase 1 of SMP pairing, the feature exchange. Takes in the current pairing state
// and notifies a constructor-provided callback with the negotiated features upon completion.
// 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 Phase1's creation thread.
class Phase1 final : public PairingPhase, public PairingChannelHandler {
// Called when Phase 1 completes successfully. |features| are the negotiated features. |preq| and
// |pres| are the SMP "Pairing Request" and "Pairing Response" payloads exchanged by the devices,
// which are returned for use in Phase 2 crypto calculations.
using CompleteCallback = fit::function<void(PairingFeatures features, PairingRequestParams preq,
PairingResponseParams pres)>;
// Returns a Phase 1 that starts pairing to |requested_level|. Note the lack of a `preq`
// parameter: Phase 1 builds & sends the Pairing Request as initiator.
static std::unique_ptr<Phase1> CreatePhase1Initiator(fxl::WeakPtr<PairingChannel> chan,
fxl::WeakPtr<Listener> listener,
IOCapability io_capability,
BondableMode bondable_mode,
SecurityLevel requested_level,
CompleteCallback on_complete);
// Returns a Phase 1 in the responder role. Note the `preq` parameter: Phase 1 is supplied the
// Pairing Request from the remote as responder. See private ctor for parameter descriptions.
static std::unique_ptr<Phase1> CreatePhase1Responder(
fxl::WeakPtr<PairingChannel> chan, fxl::WeakPtr<Listener> listener, PairingRequestParams preq,
IOCapability io_capability, BondableMode bondable_mode, SecurityLevel requested_level,
CompleteCallback on_complete);
~Phase1() override = default;
// Runs the Phase 1 state machine, performing the feature exchange.
void Start() final;
// |chan|, |listener|, and |role|: used to construct the base PairingPhase
// |preq|: If empty, the device is in the initiator role and starts the pairing.
// If present, the device is in the responder role, and will respond to |preq|, the
// peer initiator's pairing request.
// |bondable_mode|: the bondable mode of the local device (see V5.1 Vol. 3 Part C Section 9.4).
// |requested_level|: The minimum security level required by the local device for this pairing.
// Must be at least SecurityLevel::kEncrypted. If authenticated, the ctor
// ASSERTs that |io_capabilities| can perform authenticated pairing.
// |on_complete|: called at the end of Phase 1 with the resulting features.
Phase1(fxl::WeakPtr<PairingChannel> chan, fxl::WeakPtr<Listener> listener, Role role,
std::optional<PairingRequestParams> preq, IOCapability io_capability,
BondableMode bondable_mode, SecurityLevel requested_level, CompleteCallback on_complete);
// Start the feature exchange by sending the Pairing Request. The local device must be in the SMP
// initiator role (V5.1 Vol 3, Part H, 2.3).
void InitiateFeatureExchange();
// Handle the peer-initiated feature exchange. The local device must be in the SMP responder role
// (V5.1 Vol 3, Part H, 2.3).
void RespondToPairingRequest(const PairingRequestParams& req_params);
// The returned `LocalPairingParams` structure contains the locally-preferred pairing parameters.
// The caller is responsible for making any adjustments necessary (e.g. due to peer preferences)
// before converting the `LocalPairingParams` to SMP PairingResponse/PairingRequest PDUs.
LocalPairingParams BuildPairingParameters();
// Called to complete a feature exchange. Returns the resulting PairingFeatures if the parameters
// should be accepted, or an error code if the parameters are rejected and pairing should abort.
fit::result<PairingFeatures, ErrorCode> ResolveFeatures(bool local_initiator,
const PairingRequestParams& preq,
const PairingResponseParams& pres);
// Called for SMP commands sent by the peer.
void OnPairingResponse(const PairingResponseParams& response_params);
// PairingChannelHandler callbacks:
void OnRxBFrame(ByteBufferPtr sdu) final;
void OnChannelClosed() final { PairingPhase::HandleChannelClosed(); }
// PairingPhase override
fxl::WeakPtr<PairingChannelHandler> AsChannelHandler() final {
return weak_ptr_factory_.GetWeakPtr();
// If acting as the Responder to a peer-initiatied pairing, then |preq_| is the |preq| ctor
// parameter. Otherwise, these are generated and exchanged during Phase 1.
std::optional<PairingRequestParams> preq_;
std::optional<PairingResponseParams> pres_;
// Phase 1 ensures that the feature exchange results in a pairing that supports this level of
// security. If this is impossible, pairing will abort.
SecurityLevel requested_level_;
// Local feature flags that determine the feature exchange negotiation with the peer.
bool oob_available_;
IOCapability io_capability_;
BondableMode bondable_mode_;
CompleteCallback on_complete_;
fxl::WeakPtrFactory<Phase1> weak_ptr_factory_;
} // namespace sm
} // namespace bt