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 <pw_assert/check.h> 17 18 #include <unordered_map> 19 20 #include "pw_bluetooth_sapphire/internal/host/common/byte_buffer.h" 21 #include "pw_bluetooth_sapphire/internal/host/l2cap/channel.h" 22 #include "pw_bluetooth_sapphire/internal/host/l2cap/scoped_channel.h" 23 #include "pw_bluetooth_sapphire/internal/host/sm/packet.h" 24 #include "pw_bluetooth_sapphire/internal/host/sm/util.h" 25 26 namespace bt::sm { 27 28 // Bridge class for the SMP L2CAP channel, which implements SM-specific 29 // functionality on top of existing L2CAP functionality. Besides this 30 // SM-specific functionality, also allows runtime modification of L2CAP event 31 // callbacks by changing the PairingChannel::Handler pointer. 32 33 class PairingChannel { 34 public: 35 // Interface for receiving L2CAP channel events. 36 class Handler { 37 public: 38 virtual ~Handler() = default; 39 virtual void OnRxBFrame(ByteBufferPtr) = 0; 40 virtual void OnChannelClosed() = 0; 41 42 using WeakPtr = WeakSelf<Handler>::WeakPtr; 43 }; 44 45 // Initializes this PairingChannel with the L2CAP SMP fixed channel that this 46 // class wraps and the specified timer reset method. For use in production 47 // code. 48 PairingChannel(l2cap::Channel::WeakPtr chan, fit::closure timer_resetter); 49 50 // Initializes this PairingChannel with a no-op timer reset method. Only for 51 // use in tests of classes which do not depend on the timer reset behavior. 52 explicit PairingChannel(l2cap::Channel::WeakPtr chan); 53 54 // For setting the new handler, expected to be used when switching phases. 55 // PairingChannel is not fully initialized until SetChannelHandler has been 56 // called with a valid Handler. This two-phase initialization exists because 57 // concrete Handlers are expected to depend on PairingChannels. 58 void SetChannelHandler(Handler::WeakPtr new_handler); 59 60 // Wrapper which encapsulates some of the boilerplate involved in sending an 61 // SMP object. 62 template <typename PayloadType> SendMessage(Code message_code,const PayloadType & payload)63 void SendMessage(Code message_code, const PayloadType& payload) { 64 SendMessageNoTimerReset(message_code, payload); 65 reset_timer_(); 66 } 67 68 // This method exists for situations when we send messages while not pairing 69 // (e.g. rejection of pairing), where we do not want to reset the SMP timer 70 // upon transmission. 71 template <typename PayloadType> SendMessageNoTimerReset(Code message_code,const PayloadType & payload)72 void SendMessageNoTimerReset(Code message_code, const PayloadType& payload) { 73 auto kExpectedSize = kCodeToPayloadSize.find(message_code); 74 PW_CHECK(kExpectedSize != kCodeToPayloadSize.end()); 75 PW_CHECK(sizeof(PayloadType) == kExpectedSize->second); 76 auto pdu = util::NewPdu(sizeof(PayloadType)); 77 PacketWriter writer(message_code, pdu.get()); 78 *writer.mutable_payload<PayloadType>() = payload; 79 chan_->Send(std::move(pdu)); 80 } 81 82 using WeakPtr = WeakSelf<PairingChannel>::WeakPtr; GetWeakPtr()83 PairingChannel::WeakPtr GetWeakPtr() { return weak_self_.GetWeakPtr(); } 84 SupportsSecureConnections()85 bool SupportsSecureConnections() const { 86 return chan_->max_rx_sdu_size() >= kLeSecureConnectionsMtu && 87 chan_->max_tx_sdu_size() >= kLeSecureConnectionsMtu; 88 } 89 SignalLinkError()90 void SignalLinkError() { chan_->SignalLinkError(); } link_type()91 bt::LinkType link_type() const { return chan_->link_type(); } 92 ~PairingChannel() = default; 93 94 private: 95 // Used to delegate the L2CAP callbacks to the current handler 96 void OnRxBFrame(ByteBufferPtr ptr); 97 void OnChannelClosed(); 98 99 // The L2CAP Channel this class wraps. Uses a ScopedChannel because a 100 // PairingChannel is expected to own the lifetime of the underlying L2CAP 101 // channel. 102 l2cap::ScopedChannel chan_; 103 104 // Per v5.2 Vol. 3 Part H 3.4, "The Security Manager Timer shall be reset when 105 // an L2CAP SMP command is queued for transmission". This closure signals this 106 // reset to occur. 107 fit::closure reset_timer_; 108 109 // L2CAP channel events are delegated to this handler. 110 Handler::WeakPtr handler_; 111 112 WeakSelf<PairingChannel> weak_self_; 113 BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(PairingChannel); 114 }; 115 116 } // namespace bt::sm 117