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