xref: /aosp_15_r20/external/pigweed/pw_bluetooth_sapphire/host/testing/fake_sdp_server_test.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
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/testing/fake_sdp_server.h"
16 
17 #include <pw_async/fake_dispatcher_fixture.h>
18 
19 #include "pw_bluetooth_sapphire/internal/host/common/byte_buffer.h"
20 #include "pw_bluetooth_sapphire/internal/host/hci-spec/protocol.h"
21 #include "pw_bluetooth_sapphire/internal/host/l2cap/l2cap_defs.h"
22 #include "pw_bluetooth_sapphire/internal/host/l2cap/test_packets.h"
23 #include "pw_bluetooth_sapphire/internal/host/testing/fake_dynamic_channel.h"
24 #include "pw_bluetooth_sapphire/internal/host/testing/fake_l2cap.h"
25 #include "pw_bluetooth_sapphire/internal/host/testing/fake_signaling_server.h"
26 #include "pw_bluetooth_sapphire/internal/host/testing/test_helpers.h"
27 
28 namespace bt::testing {
29 namespace {
30 
31 l2cap::ChannelParameters kChannelParams;
32 hci_spec::ConnectionHandle kConnectionHandle = 0x01;
33 l2cap::CommandId kCommandId = 0x02;
34 l2cap::Psm kPsm = l2cap::kSDP;
35 l2cap::ChannelId src_id = l2cap::kFirstDynamicChannelId;
36 
SdpErrorResponse(uint16_t t_id,sdp::ErrorCode code)37 auto SdpErrorResponse(uint16_t t_id, sdp::ErrorCode code) {
38   return StaticByteBuffer(0x01,
39                           UpperBits(t_id),
40                           LowerBits(t_id),
41                           0x00,
42                           0x02,
43                           UpperBits(uint16_t(code)),
44                           LowerBits(uint16_t(code)));
45 }
46 
GetSPPServiceRecord()47 std::vector<sdp::ServiceRecord> GetSPPServiceRecord() {
48   sdp::ServiceRecord record;
49   record.SetServiceClassUUIDs({sdp::profile::kSerialPort});
50   record.AddProtocolDescriptor(sdp::ServiceRecord::kPrimaryProtocolList,
51                                sdp::protocol::kL2CAP,
52                                sdp::DataElement());
53   record.AddProtocolDescriptor(sdp::ServiceRecord::kPrimaryProtocolList,
54                                sdp::protocol::kRFCOMM,
55                                sdp::DataElement(uint8_t{0}));
56   record.AddProfile(sdp::profile::kSerialPort, 1, 2);
57   record.AddInfo("en", "FAKE", "", "");
58   std::vector<sdp::ServiceRecord> records;
59   records.emplace_back(std::move(record));
60   return records;
61 }
62 
GetA2DPServiceRecord()63 std::vector<sdp::ServiceRecord> GetA2DPServiceRecord() {
64   sdp::ServiceRecord record;
65   record.SetServiceClassUUIDs({sdp::profile::kAudioSink});
66   record.AddProtocolDescriptor(sdp::ServiceRecord::kPrimaryProtocolList,
67                                sdp::protocol::kL2CAP,
68                                sdp::DataElement(l2cap::kAVDTP));
69   record.AddProtocolDescriptor(sdp::ServiceRecord::kPrimaryProtocolList,
70                                sdp::protocol::kAVDTP,
71                                sdp::DataElement(uint16_t{0x0103}));  // Version
72   record.AddProfile(sdp::profile::kAdvancedAudioDistribution, 1, 3);
73   record.SetAttribute(sdp::kA2DP_SupportedFeatures,
74                       sdp::DataElement(uint16_t{0x0001}));  // Headphones
75   std::vector<sdp::ServiceRecord> records;
76   records.emplace_back(std::move(record));
77   return records;
78 }
79 
80 #define UINT32_AS_BE_BYTES(x)                                    \
81   UpperBits(x >> 16), LowerBits(x >> 16), UpperBits(x & 0xFFFF), \
82       LowerBits(x & 0xFFFF)
83 
84 using FakeSdpServerTest = pw::async::test::FakeDispatcherFixture;
85 
TEST_F(FakeSdpServerTest,SuccessfulSearch)86 TEST_F(FakeSdpServerTest, SuccessfulSearch) {
87   std::unique_ptr<ByteBuffer> sent_packet;
88   auto send_cb = [&sent_packet](auto& buffer) {
89     sent_packet = std::make_unique<DynamicByteBuffer>(buffer);
90   };
91   FakeDynamicChannel channel(kConnectionHandle, kCommandId, src_id, src_id);
92   channel.set_send_packet_callback(send_cb);
93   channel.set_opened();
94   auto sdp_server = FakeSdpServer(dispatcher());
95 
96   // Configure the SDP server to provide a response to the search.
97   auto NopConnectCallback = [](auto /*channel*/, const sdp::DataElement&) {};
98   sdp::Server::RegistrationHandle spp_handle =
99       sdp_server.server()->RegisterService(
100           GetSPPServiceRecord(), kChannelParams, NopConnectCallback);
101   EXPECT_TRUE(spp_handle);
102   sdp::Server::RegistrationHandle a2dp_handle =
103       sdp_server.server()->RegisterService(
104           GetA2DPServiceRecord(), kChannelParams, NopConnectCallback);
105   EXPECT_TRUE(a2dp_handle);
106   const StaticByteBuffer kL2capSearch(
107       0x02,  // SDP_ServiceSearchRequest
108       0x10,
109       0x01,  // Transaction ID (0x1001)
110       0x00,
111       0x08,  // Parameter length (8 bytes)
112       // ServiceSearchPattern
113       0x35,
114       0x03,  // Sequence uint8 3 bytes
115       0x19,
116       0x01,
117       0x00,  // UUID: Protocol: L2CAP
118       0xFF,
119       0xFF,  // MaximumServiceRecordCount: (none)
120       0x00   // Contunuation State: none
121   );
122   const StaticByteBuffer kL2capSearchResponse(
123       0x03,  // SDP_ServicesearchResponse
124       0x10,
125       0x01,  // Transaction ID (0x1001)
126       0x00,
127       0x0D,  // Parameter length (13 bytes)
128       0x00,
129       0x02,  // Total service record count: 2
130       0x00,
131       0x02,                             // Current service record count: 2
132       UINT32_AS_BE_BYTES(a2dp_handle),  // This list isn't specifically ordered
133       UINT32_AS_BE_BYTES(spp_handle),
134       0x00  // No continuation state
135   );
136   sdp_server.HandleSdu(channel.AsWeakPtr(), kL2capSearch);
137   EXPECT_TRUE(ContainersEqual(kL2capSearchResponse, *sent_packet));
138 }
139 
TEST_F(FakeSdpServerTest,ErrorIfTooSmall)140 TEST_F(FakeSdpServerTest, ErrorIfTooSmall) {
141   std::unique_ptr<ByteBuffer> sent_packet;
142   auto send_cb = [&sent_packet](auto& buffer) {
143     sent_packet = std::make_unique<DynamicByteBuffer>(buffer);
144   };
145   FakeDynamicChannel channel(kConnectionHandle, kCommandId, src_id, src_id);
146   channel.set_send_packet_callback(send_cb);
147   channel.set_opened();
148   auto sdp_server = FakeSdpServer(dispatcher());
149 
150   // Expect an error response if the packet is too small
151   const StaticByteBuffer kTooSmall(0x01,  // SDP_ServiceSearchRequest
152                                    0x10,
153                                    0x01,  // Transaction ID (0x1001)
154                                    0x00,
155                                    0x09  // Parameter length (9 bytes)
156   );
157   const auto kRspTooSmall =
158       SdpErrorResponse(0x1001, sdp::ErrorCode::kInvalidSize);
159   sdp_server.HandleSdu(channel.AsWeakPtr(), kTooSmall);
160   EXPECT_TRUE(ContainersEqual(kRspTooSmall, *sent_packet));
161 }
162 
TEST_F(FakeSdpServerTest,RegisterWithL2cap)163 TEST_F(FakeSdpServerTest, RegisterWithL2cap) {
164   std::unique_ptr<ByteBuffer> received_packet;
165   auto send_cb = [&received_packet](auto /*conn*/, auto /*cid*/, auto& buffer) {
166     received_packet = std::make_unique<DynamicByteBuffer>(buffer);
167   };
168   auto fake_l2cap = FakeL2cap(send_cb);
169   auto sdp_server = std::make_unique<FakeSdpServer>(dispatcher());
170   sdp_server->RegisterWithL2cap(&fake_l2cap);
171   EXPECT_TRUE(fake_l2cap.ServiceRegisteredForPsm(kPsm));
172 }
173 
174 }  // namespace
175 }  // namespace bt::testing
176