text: // 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.
  
  #ifndef SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_SM_PHASE_1_H_
  #define SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_SM_PHASE_1_H_
  
  #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::sm {
  // Responsible for Phase 1 of SMP pairing, the feature exchange. Takes in the current SM settings
  // 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 {
   public:
    // 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;
  
   private:
    //   |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` contains the locally-preferred pairing parameters for the LE
    // transport. The caller is responsible for making any adjustments necessary (e.g. due to peer
    // preferences) before converting the `LocalPairingParams` to SMP Pairing(Response|Request) 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.
    fpromise::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 overrides
    fxl::WeakPtr<PairingChannelHandler> AsChannelHandler() final {
      return weak_ptr_factory_.GetWeakPtr();
    }
  
    std::string ToStringInternal() override {
      return fxl::StringPrintf(
          "Pairing Phase 1 (feature exchange) - pairing to %s security with \"%s\" IOCapabilities",
          LevelToString(requested_level_), util::IOCapabilityToString(io_capability_).c_str());
    }
  
    // 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_;
  
    DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(Phase1);
  };
  
  }  // namespace bt::sm
  
  #endif  // SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_SM_PHASE_1_H_
  