• 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 #include "pw_bluetooth_sapphire/internal/host/testing/fake_peer.h"
16 
17 #include <endian.h>
18 
19 #include "pw_bluetooth_sapphire/internal/host/common/assert.h"
20 #include "pw_bluetooth_sapphire/internal/host/common/log.h"
21 #include "pw_bluetooth_sapphire/internal/host/common/packet_view.h"
22 #include "pw_bluetooth_sapphire/internal/host/l2cap/l2cap_defs.h"
23 #include "pw_bluetooth_sapphire/internal/host/testing/fake_controller.h"
24 
25 namespace bt::testing {
26 using pw::bluetooth::emboss::LEExtendedAdvertisingReportDataWriter;
27 
FakePeer(const DeviceAddress & address,pw::async::Dispatcher & pw_dispatcher,bool connectable,bool scannable)28 FakePeer::FakePeer(const DeviceAddress& address,
29                    pw::async::Dispatcher& pw_dispatcher,
30                    bool connectable,
31                    bool scannable)
32     : controller_(nullptr),
33       address_(address),
34       name_("FakePeer"),
35       connected_(false),
36       connectable_(connectable),
37       scannable_(scannable),
38       advertising_enabled_(true),
39       directed_(false),
40       address_resolved_(false),
41       connect_status_(pw::bluetooth::emboss::StatusCode::SUCCESS),
42       connect_response_(pw::bluetooth::emboss::StatusCode::SUCCESS),
43       force_pending_connect_(false),
44       supports_ll_conn_update_procedure_(true),
45       le_features_(hci_spec::LESupportedFeatures{0}),
46       should_batch_reports_(false),
47       l2cap_(fit::bind_member<&FakePeer::SendPacket>(this)),
48       gatt_server_(this),
49       sdp_server_(pw_dispatcher) {
50   signaling_server_.RegisterWithL2cap(&l2cap_);
51   gatt_server_.RegisterWithL2cap(&l2cap_);
52   sdp_server_.RegisterWithL2cap(&l2cap_);
53 }
54 
set_scan_response(bool should_batch_reports,const ByteBuffer & data)55 void FakePeer::set_scan_response(bool should_batch_reports,
56                                  const ByteBuffer& data) {
57   BT_DEBUG_ASSERT(scannable_);
58   scan_rsp_ = DynamicByteBuffer(data);
59   should_batch_reports_ = should_batch_reports;
60 }
61 
CreateInquiryResponseEvent(pw::bluetooth::emboss::InquiryMode mode) const62 DynamicByteBuffer FakePeer::CreateInquiryResponseEvent(
63     pw::bluetooth::emboss::InquiryMode mode) const {
64   BT_DEBUG_ASSERT(address_.type() == DeviceAddress::Type::kBREDR);
65 
66   if (mode == pw::bluetooth::emboss::InquiryMode::STANDARD) {
67     size_t packet_size =
68         pw::bluetooth::emboss::InquiryResultEvent::MinSizeInBytes() +
69         pw::bluetooth::emboss::InquiryResult::IntrinsicSizeInBytes();
70     auto packet = hci::EmbossEventPacket::New<
71         pw::bluetooth::emboss::InquiryResultEventWriter>(
72         hci_spec::kInquiryResultEventCode, packet_size);
73     auto view = packet.view_t();
74     view.num_responses().Write(1);
75     view.responses()[0].bd_addr().CopyFrom(address_.value().view());
76     view.responses()[0].page_scan_repetition_mode().Write(
77         pw::bluetooth::emboss::PageScanRepetitionMode::R0_);
78     view.responses()[0].class_of_device().BackingStorage().WriteUInt(
79         class_of_device_.to_int());
80     return DynamicByteBuffer{packet.data()};
81   }
82 
83   constexpr size_t packet_size =
84       pw::bluetooth::emboss::InquiryResultWithRssiEvent::MinSizeInBytes() +
85       pw::bluetooth::emboss::InquiryResultWithRssi::IntrinsicSizeInBytes();
86   auto packet = hci::EmbossEventPacket::New<
87       pw::bluetooth::emboss::InquiryResultWithRssiEventWriter>(
88       hci_spec::kInquiryResultEventCode, packet_size);
89   auto view = packet.view_t();
90 
91   // TODO(jamuraa): simulate clock offset and RSSI
92   view.num_responses().Write(1);
93   auto response = view.responses()[0];
94   response.bd_addr().CopyFrom(address_.value().view());
95   response.page_scan_repetition_mode().Write(
96       pw::bluetooth::emboss::PageScanRepetitionMode::R0_);
97   response.class_of_device().BackingStorage().WriteUInt(
98       class_of_device_.to_int());
99   response.clock_offset().BackingStorage().WriteUInt(0);
100   response.rssi().Write(-30);
101   return DynamicByteBuffer{packet.data()};
102 }
103 
AddLink(hci_spec::ConnectionHandle handle)104 void FakePeer::AddLink(hci_spec::ConnectionHandle handle) {
105   BT_DEBUG_ASSERT(!HasLink(handle));
106   logical_links_.insert(handle);
107 
108   if (logical_links_.size() == 1u) {
109     set_connected(true);
110   }
111 }
112 
RemoveLink(hci_spec::ConnectionHandle handle)113 void FakePeer::RemoveLink(hci_spec::ConnectionHandle handle) {
114   BT_DEBUG_ASSERT(HasLink(handle));
115   logical_links_.erase(handle);
116   if (logical_links_.empty())
117     set_connected(false);
118 }
119 
HasLink(hci_spec::ConnectionHandle handle) const120 bool FakePeer::HasLink(hci_spec::ConnectionHandle handle) const {
121   return logical_links_.count(handle) != 0u;
122 }
123 
Disconnect()124 FakePeer::HandleSet FakePeer::Disconnect() {
125   set_connected(false);
126   return std::move(logical_links_);
127 }
128 
OnRxL2CAP(hci_spec::ConnectionHandle conn,const ByteBuffer & pdu)129 void FakePeer::OnRxL2CAP(hci_spec::ConnectionHandle conn,
130                          const ByteBuffer& pdu) {
131   if (pdu.size() < sizeof(l2cap::BasicHeader)) {
132     bt_log(WARN, "fake-hci", "malformed L2CAP packet!");
133     return;
134   }
135   l2cap_.HandlePdu(conn, pdu);
136 }
137 
SendPacket(hci_spec::ConnectionHandle conn,l2cap::ChannelId cid,const ByteBuffer & packet) const138 void FakePeer::SendPacket(hci_spec::ConnectionHandle conn,
139                           l2cap::ChannelId cid,
140                           const ByteBuffer& packet) const {
141   controller()->SendL2CAPBFrame(conn, cid, packet);
142 }
143 
144 }  // namespace bt::testing
145