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