• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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