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 #include "pw_bluetooth_sapphire/internal/host/sm/pairing_channel.h"
16
17 #include <memory>
18
19 #include "lib/fit/function.h"
20 #include "pw_bluetooth_sapphire/internal/host/common/byte_buffer.h"
21 #include "pw_bluetooth_sapphire/internal/host/hci-spec/protocol.h"
22 #include "pw_bluetooth_sapphire/internal/host/hci/connection.h"
23 #include "pw_bluetooth_sapphire/internal/host/l2cap/mock_channel_test.h"
24 #include "pw_bluetooth_sapphire/internal/host/sm/smp.h"
25 #include "pw_bluetooth_sapphire/internal/host/sm/util.h"
26 #include "pw_bluetooth_sapphire/internal/host/testing/test_helpers.h"
27
28 namespace bt::sm {
29 namespace {
30
31 class FakeChannelHandler : public PairingChannel::Handler {
32 public:
FakeChannelHandler()33 FakeChannelHandler() : weak_self_(this) {}
34
OnRxBFrame(ByteBufferPtr data)35 void OnRxBFrame(ByteBufferPtr data) override {
36 last_rx_data_ = std::move(data);
37 frames_received_++;
38 }
39
OnChannelClosed()40 void OnChannelClosed() override { channel_closed_count_++; }
41
last_rx_data()42 ByteBuffer* last_rx_data() { return last_rx_data_.get(); }
43
frames_received() const44 int frames_received() const { return frames_received_; }
channel_closed_count() const45 int channel_closed_count() const { return channel_closed_count_; }
as_weak_handler()46 PairingChannel::Handler::WeakPtr as_weak_handler() {
47 return weak_self_.GetWeakPtr();
48 }
49
50 private:
51 ByteBufferPtr last_rx_data_ = nullptr;
52 int frames_received_ = 0;
53 int channel_closed_count_ = 0;
54 WeakSelf<PairingChannel::Handler> weak_self_;
55 };
56
57 class PairingChannelTest : public l2cap::testing::MockChannelTest {
58 protected:
SetUp()59 void SetUp() override { NewPairingChannel(); }
60
TearDown()61 void TearDown() override { sm_chan_ = nullptr; }
62
NewPairingChannel(bt::LinkType ll_type=bt::LinkType::kLE,uint16_t mtu=kNoSecureConnectionsMtu)63 void NewPairingChannel(bt::LinkType ll_type = bt::LinkType::kLE,
64 uint16_t mtu = kNoSecureConnectionsMtu) {
65 l2cap::ChannelId cid = ll_type == bt::LinkType::kLE ? l2cap::kLESMPChannelId
66 : l2cap::kSMPChannelId;
67 ChannelOptions options(cid, mtu);
68 options.link_type = ll_type;
69 fake_sm_chan_ = CreateFakeChannel(options);
70 sm_chan_ = std::make_unique<PairingChannel>(
71 fake_sm_chan_->GetWeakPtr(),
72 fit::bind_member<&PairingChannelTest::ResetTimer>(this));
73 }
74
sm_chan()75 PairingChannel* sm_chan() { return sm_chan_.get(); }
set_timer_resetter(fit::closure timer_resetter)76 void set_timer_resetter(fit::closure timer_resetter) {
77 timer_resetter_ = std::move(timer_resetter);
78 }
79
80 private:
ResetTimer()81 void ResetTimer() { timer_resetter_(); }
82
83 l2cap::testing::FakeChannel::WeakPtr fake_sm_chan_;
84 std::unique_ptr<PairingChannel> sm_chan_;
__anonc6c092f20202() 85 fit::closure timer_resetter_ = []() {};
86 };
87
88 using PairingChannelDeathTest = PairingChannelTest;
TEST_F(PairingChannelDeathTest,L2capChannelMtuTooSmallDies)89 TEST_F(PairingChannelDeathTest, L2capChannelMtuTooSmallDies) {
90 ASSERT_DEATH_IF_SUPPORTED(
91 NewPairingChannel(bt::LinkType::kLE, kNoSecureConnectionsMtu - 1),
92 ".*max.*_sdu_size.*");
93 }
94
TEST_F(PairingChannelDeathTest,SendInvalidMessageDies)95 TEST_F(PairingChannelDeathTest, SendInvalidMessageDies) {
96 // Tests that an invalid SMP code aborts the process
97 EXPECT_DEATH_IF_SUPPORTED(
98 sm_chan()->SendMessage(0xFF, ErrorCode::kUnspecifiedReason), ".*end.*");
99
100 // Tests that a valid SMP code with a mismatched payload aborts the process
101 EXPECT_DEATH_IF_SUPPORTED(
102 sm_chan()->SendMessage(kPairingFailed, PairingRequestParams{}),
103 ".*sizeof.*");
104 }
105
TEST_F(PairingChannelTest,SendMessageWorks)106 TEST_F(PairingChannelTest, SendMessageWorks) {
107 PairingRandomValue kExpectedPayload = {1, 2, 3, 4, 5};
108 StaticByteBuffer<util::PacketSize<PairingRandomValue>()> kExpectedPacket;
109 PacketWriter w(kPairingRandom, &kExpectedPacket);
110 *w.mutable_payload<PairingRandomValue>() = kExpectedPayload;
111 bool timer_reset = false;
112 set_timer_resetter([&]() { timer_reset = true; });
113 EXPECT_PACKET_OUT(kExpectedPacket);
114 sm_chan()->SendMessage(kPairingRandom, kExpectedPayload);
115 RunUntilIdle();
116 ASSERT_TRUE(timer_reset);
117 }
118
119 // This checks that PairingChannel doesn't crash when receiving events without a
120 // handler set.
TEST_F(PairingChannelTest,NoHandlerSetDataDropped)121 TEST_F(PairingChannelTest, NoHandlerSetDataDropped) {
122 ASSERT_TRUE(sm_chan());
123 const StaticByteBuffer kSmPacket(kPairingFailed,
124 ErrorCode::kPairingNotSupported);
125
126 fake_chan()->Receive(kSmPacket);
127 RunUntilIdle();
128
129 fake_chan()->Close();
130 RunUntilIdle();
131 }
132
TEST_F(PairingChannelTest,SetHandlerReceivesData)133 TEST_F(PairingChannelTest, SetHandlerReceivesData) {
134 ASSERT_TRUE(sm_chan());
135 const StaticByteBuffer kSmPacket1(kPairingFailed,
136 ErrorCode::kPairingNotSupported);
137 const StaticByteBuffer kSmPacket2(kPairingFailed,
138 ErrorCode::kConfirmValueFailed);
139 FakeChannelHandler handler;
140 sm_chan()->SetChannelHandler(handler.as_weak_handler());
141 ASSERT_EQ(handler.last_rx_data(), nullptr);
142 ASSERT_EQ(handler.frames_received(), 0);
143
144 fake_chan()->Receive(kSmPacket1);
145 RunUntilIdle();
146 ASSERT_NE(handler.last_rx_data(), nullptr);
147 EXPECT_TRUE(ContainersEqual(*handler.last_rx_data(), kSmPacket1));
148 ASSERT_EQ(handler.frames_received(), 1);
149
150 fake_chan()->Receive(kSmPacket2);
151 RunUntilIdle();
152 ASSERT_NE(handler.last_rx_data(), nullptr);
153 EXPECT_TRUE(ContainersEqual(*handler.last_rx_data(), kSmPacket2));
154 ASSERT_EQ(handler.frames_received(), 2);
155
156 fake_chan()->Close();
157 RunUntilIdle();
158 ASSERT_EQ(handler.channel_closed_count(), 1);
159 }
160
TEST_F(PairingChannelTest,ChangeHandlerNewHandlerReceivesData)161 TEST_F(PairingChannelTest, ChangeHandlerNewHandlerReceivesData) {
162 ASSERT_TRUE(sm_chan());
163 const StaticByteBuffer kSmPacket1(kPairingFailed,
164 ErrorCode::kPairingNotSupported);
165 const StaticByteBuffer kSmPacket2(kPairingFailed,
166 ErrorCode::kConfirmValueFailed);
167 FakeChannelHandler handler;
168 sm_chan()->SetChannelHandler(handler.as_weak_handler());
169 ASSERT_EQ(handler.last_rx_data(), nullptr);
170 ASSERT_EQ(handler.frames_received(), 0);
171
172 fake_chan()->Receive(kSmPacket1);
173 RunUntilIdle();
174 ASSERT_NE(handler.last_rx_data(), nullptr);
175 EXPECT_TRUE(ContainersEqual(*handler.last_rx_data(), kSmPacket1));
176 ASSERT_EQ(handler.frames_received(), 1);
177
178 FakeChannelHandler new_handler;
179 ASSERT_EQ(new_handler.last_rx_data(), nullptr);
180 sm_chan()->SetChannelHandler(new_handler.as_weak_handler());
181 fake_chan()->Receive(kSmPacket2);
182 RunUntilIdle();
183 ASSERT_NE(new_handler.last_rx_data(), nullptr);
184 EXPECT_TRUE(ContainersEqual(*new_handler.last_rx_data(), kSmPacket2));
185 ASSERT_EQ(new_handler.frames_received(), 1);
186 // Check handler's data hasn't changed.
187 EXPECT_TRUE(ContainersEqual(*handler.last_rx_data(), kSmPacket1));
188 ASSERT_EQ(handler.frames_received(), 1);
189
190 fake_chan()->Close();
191 RunUntilIdle();
192 ASSERT_EQ(new_handler.channel_closed_count(), 1);
193 ASSERT_EQ(handler.channel_closed_count(), 0);
194 }
195 } // namespace
196 } // namespace bt::sm
197