1 // Copyright 2023 The Pigweed Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not 4 // use this file except in compliance with the License. You may obtain a copy of 5 // the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 // License for the specific language governing permissions and limitations under 13 // the License. 14 15 #pragma once 16 #include <cpp-string/string_printf.h> 17 18 #include <string> 19 20 #include "pw_bluetooth_sapphire/internal/host/hci/connection.h" 21 #include "pw_bluetooth_sapphire/internal/host/sm/pairing_channel.h" 22 #include "pw_bluetooth_sapphire/internal/host/sm/types.h" 23 24 namespace bt::sm { 25 26 // Abstract class representing one of the four in-progress phases of pairing 27 // described in Vol. 3 Part H 2.1. 28 // 29 // After a PairingPhase fails (i.e. through calling OnFailure), it is invalid to 30 // make any further method calls on the phase. 31 using PairingChannelHandler = PairingChannel::Handler; 32 class PairingPhase { 33 public: 34 // Interface for notifying the owner of the phase object. 35 class Listener { 36 public: 37 virtual ~Listener() = default; 38 39 // Polls for the local identity information, which must be handled by 40 // another component of the Bluetooth stack. Returns std::nullopt if no 41 // local identity info is available. 42 virtual std::optional<IdentityInfo> OnIdentityRequest() = 0; 43 44 using ConfirmCallback = fit::function<void(bool confirm)>; 45 virtual void ConfirmPairing(ConfirmCallback confirm) = 0; 46 47 // Show the user the 6-digit |passkey| that should be compared to the peer's 48 // passkey or entered into the peer. |confirm| may be called to accept a 49 // comparison or to reject the pairing. 50 virtual void DisplayPasskey(uint32_t passkey, 51 Delegate::DisplayMethod method, 52 ConfirmCallback confirm) = 0; 53 54 // Ask the user to enter a 6-digit passkey or reject pairing. Reports the 55 // result by invoking |respond| with |passkey| - a negative value of 56 // |passkey| indicates entry failed. 57 // TODO(fxbug.dev/42126992): Use an optional to convey success/failure 58 // instead of the signedness of passkey. 59 using PasskeyResponseCallback = fit::function<void(int64_t passkey)>; 60 virtual void RequestPasskey(PasskeyResponseCallback respond) = 0; 61 62 // Called when an on-going pairing procedure terminates with an error. This 63 // method should destroy the Phase that calls it. 64 virtual void OnPairingFailed(Error error) = 0; 65 66 using WeakPtr = WeakSelf<Listener>::WeakPtr; 67 }; 68 69 virtual ~PairingPhase() = default; 70 71 // Kick off the state machine for the concrete PairingPhase. 72 virtual void Start() = 0; 73 74 // Return a representation of the current state of the pairing phase for 75 // display purposes. ToString()76 std::string ToString() { 77 return bt_lib_cpp_string::StringPrintf( 78 "%s Role: SMP %s%s", 79 ToStringInternal().c_str(), 80 role_ == Role::kInitiator ? "initiator" : "responder", 81 has_failed_ ? " - pairing has failed" : ""); 82 } 83 84 // Cleans up pairing state and and invokes Listener::OnPairingFailed. 85 void OnFailure(Error error); 86 87 // Ends the current pairing procedure unsuccessfully with |ecode| as the 88 // reason, and calls OnFailure. 89 void Abort(ErrorCode ecode); 90 role()91 Role role() const { return role_; } 92 93 protected: 94 // Protected constructor as PairingPhases should not be created directly. 95 // Initializes this PairingPhase with the following parameters: 96 // - |chan|: The L2CAP SMP fixed channel. 97 // - |listener|: The class that will handle higher-level requests from the 98 // current phase. 99 // - |role|: The local connection role. 100 PairingPhase(PairingChannel::WeakPtr chan, 101 Listener::WeakPtr listener, 102 Role role); 103 104 // For derived final classes to implement PairingChannel::Handler: 105 void HandleChannelClosed(); 106 sm_chan()107 PairingChannel& sm_chan() const { 108 PW_CHECK(sm_chan_.is_alive()); 109 return sm_chan_.get(); 110 } 111 listener()112 Listener::WeakPtr listener() const { return listener_; } 113 114 // Concrete classes of PairingPhase must be PairingChannelHandlers and call 115 // this function when the phase is ready to handle requests. 116 void SetPairingChannelHandler(PairingChannelHandler& self); 117 118 // Invalidate handling requests to this phase. This function should only be 119 // called once during destruction of the phase. 120 void InvalidatePairingChannelHandler(); 121 122 // To BT_ASSERT that methods are not called on a phase that has already 123 // failed. has_failed()124 bool has_failed() const { return has_failed_; } 125 126 // For subclasses to provide more detailed inspect information. 127 virtual std::string ToStringInternal() = 0; 128 129 private: 130 PairingChannel::WeakPtr sm_chan_; 131 Listener::WeakPtr listener_; 132 Role role_; 133 bool has_failed_; 134 WeakSelf<PairingChannel::Handler> weak_channel_handler_; 135 BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(PairingPhase); 136 }; 137 138 } // namespace bt::sm 139