1 // Copyright 2024 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/fuchsia/bt_host/host.h"
16
17 #include <lib/fdio/directory.h>
18 #include <lib/inspect/component/cpp/component.h>
19 #include <pw_assert/check.h>
20
21 #include "lib/async/default.h"
22 #include "pw_bluetooth_sapphire/fuchsia/bt_host/bt_host_config.h"
23 #include "pw_bluetooth_sapphire/fuchsia/host/controllers/fidl_controller.h"
24 #include "pw_bluetooth_sapphire/fuchsia/host/fidl/host_server.h"
25 #include "pw_bluetooth_sapphire/internal/host/common/log.h"
26 #include "pw_bluetooth_sapphire/internal/host/common/random.h"
27
28 using namespace bt;
29
30 namespace bthost {
31
BtHostComponent(async_dispatcher_t * dispatcher,const std::string & device_path,bool initialize_rng)32 BtHostComponent::BtHostComponent(async_dispatcher_t* dispatcher,
33 const std::string& device_path,
34 bool initialize_rng)
35 : pw_dispatcher_(dispatcher),
36 device_path_(device_path),
37 initialize_rng_(initialize_rng),
38 inspector_(inspect::ComponentInspector(dispatcher, {})) {
39 if (initialize_rng) {
40 set_random_generator(&random_generator_);
41 }
42 inspector_.root().RecordString("name", device_path_);
43 }
44
~BtHostComponent()45 BtHostComponent::~BtHostComponent() {
46 if (initialize_rng_) {
47 set_random_generator(nullptr);
48 }
49 }
50
51 // static
Create(async_dispatcher_t * dispatcher,const std::string & device_path)52 std::unique_ptr<BtHostComponent> BtHostComponent::Create(
53 async_dispatcher_t* dispatcher, const std::string& device_path) {
54 std::unique_ptr<BtHostComponent> host(
55 new BtHostComponent(dispatcher, device_path, /*initialize_rng=*/true));
56 return host;
57 }
58
59 // static
CreateForTesting(async_dispatcher_t * dispatcher,const std::string & device_path)60 std::unique_ptr<BtHostComponent> BtHostComponent::CreateForTesting(
61 async_dispatcher_t* dispatcher, const std::string& device_path) {
62 std::unique_ptr<BtHostComponent> host(
63 new BtHostComponent(dispatcher, device_path, /*initialize_rng=*/false));
64 return host;
65 }
66
Initialize(fidl::ClientEnd<fuchsia_hardware_bluetooth::Vendor> vendor_client_end,InitCallback init_cb,ErrorCallback error_cb,bool legacy_pairing_enabled)67 bool BtHostComponent::Initialize(
68 fidl::ClientEnd<fuchsia_hardware_bluetooth::Vendor> vendor_client_end,
69 InitCallback init_cb,
70 ErrorCallback error_cb,
71 bool legacy_pairing_enabled) {
72 std::unique_ptr<bt::controllers::FidlController> controller =
73 std::make_unique<bt::controllers::FidlController>(
74 std::move(vendor_client_end), async_get_default_dispatcher());
75
76 bt_log(INFO, "bt-host", "Create HCI transport layer");
77 hci_ =
78 std::make_unique<hci::Transport>(std::move(controller), pw_dispatcher_);
79
80 bt_log(INFO, "bt-host", "Create GATT layer");
81 gatt_ = gatt::GATT::Create();
82 gap::Adapter::Config config = {
83 .legacy_pairing_enabled = legacy_pairing_enabled,
84 };
85 gap_ = gap::Adapter::Create(
86 pw_dispatcher_, hci_->GetWeakPtr(), gatt_->GetWeakPtr(), config);
87 if (!gap_) {
88 bt_log(WARN, "bt-host", "GAP could not be created");
89 return false;
90 }
91 gap_->AttachInspect(inspector_.root(), "adapter");
92
93 // Called when the GAP layer is ready. We initialize the GATT profile after
94 // initial setup in GAP. The data domain will be initialized by GAP because it
95 // both sets up the HCI ACL data channel that L2CAP relies on and registers
96 // L2CAP services.
97 auto gap_init_callback = [callback =
98 std::move(init_cb)](bool success) mutable {
99 bt_log(DEBUG,
100 "bt-host",
101 "GAP init complete status: (%s)",
102 (success ? "success" : "failure"));
103 callback(success);
104 };
105
106 auto transport_closed_callback = [error_cb = std::move(error_cb)]() mutable {
107 bt_log(WARN, "bt-host", "HCI transport has closed");
108 error_cb();
109 };
110
111 bt_log(DEBUG, "bt-host", "Initializing GAP");
112 return gap_->Initialize(std::move(gap_init_callback),
113 std::move(transport_closed_callback));
114 }
115
ShutDown()116 void BtHostComponent::ShutDown() {
117 bt_log(DEBUG, "bt-host", "Shutting down");
118
119 if (!gap_) {
120 bt_log(DEBUG, "bt-host", "Already shut down");
121 return;
122 }
123
124 // Closes all FIDL channels owned by |host_server_|.
125 host_server_ = nullptr;
126
127 // Make sure that |gap_| gets shut down and destroyed on its creation thread
128 // as it is not thread-safe.
129 gap_->ShutDown();
130 gap_ = nullptr;
131
132 // This shuts down the GATT profile and all of its clients.
133 gatt_ = nullptr;
134
135 // Shuts down HCI command channel and ACL data channel.
136 hci_ = nullptr;
137 }
138
BindToHostInterface(fidl::ServerEnd<fuchsia_bluetooth_host::Host> host_client)139 void BtHostComponent::BindToHostInterface(
140 fidl::ServerEnd<fuchsia_bluetooth_host::Host> host_client) {
141 if (host_server_) {
142 bt_log(WARN, "bt-host", "Host interface channel already open");
143 return;
144 }
145
146 PW_DCHECK(gap_);
147 PW_DCHECK(gatt_);
148
149 zx::channel channel = host_client.TakeChannel();
150
151 host_server_ = std::make_unique<HostServer>(
152 std::move(channel), gap_->AsWeakPtr(), gatt_->GetWeakPtr());
153 host_server_->set_error_handler([this](zx_status_t status) {
154 PW_DCHECK(host_server_);
155 bt_log(WARN, "bt-host", "Host interface disconnected");
156 host_server_ = nullptr;
157 });
158 }
159
160 } // namespace bthost
161