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