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/host/fidl/low_energy_peripheral_server.h"
16
17 #include <lib/async/default.h>
18 #include <zircon/status.h>
19
20 #include "pw_bluetooth_sapphire/fuchsia/host/fidl/helpers.h"
21 #include "pw_bluetooth_sapphire/internal/host/common/advertising_data.h"
22 #include "pw_bluetooth_sapphire/internal/host/common/assert.h"
23 #include "pw_bluetooth_sapphire/internal/host/common/identifier.h"
24 #include "pw_bluetooth_sapphire/internal/host/common/log.h"
25 #include "pw_bluetooth_sapphire/internal/host/gap/low_energy_advertising_manager.h"
26 #include "pw_bluetooth_sapphire/internal/host/gap/low_energy_connection_manager.h"
27 #include "pw_bluetooth_sapphire/internal/host/gap/peer.h"
28 #include "pw_bluetooth_sapphire/internal/host/hci-spec/constants.h"
29 #include "pw_bluetooth_sapphire/internal/host/hci-spec/util.h"
30 #include "pw_bluetooth_sapphire/internal/host/sm/types.h"
31
32 #define LOG_TAG "fidl"
33
34 using bt::sm::BondableMode;
35 namespace fble = fuchsia::bluetooth::le;
36
37 namespace bthost {
38 namespace {
39
FidlErrorFromStatus(bt::hci::Result<> status)40 fble::PeripheralError FidlErrorFromStatus(bt::hci::Result<> status) {
41 PW_CHECK(status.is_error(), "FidlErrorFromStatus called on success status");
42 return status.error_value().Visit(
43 [](bt::HostError host_error) {
44 switch (host_error) {
45 case bt::HostError::kNotSupported:
46 return fble::PeripheralError::NOT_SUPPORTED;
47 case bt::HostError::kInvalidParameters:
48 return fble::PeripheralError::INVALID_PARAMETERS;
49 case bt::HostError::kAdvertisingDataTooLong:
50 return fble::PeripheralError::ADVERTISING_DATA_TOO_LONG;
51 case bt::HostError::kScanResponseTooLong:
52 return fble::PeripheralError::SCAN_RESPONSE_DATA_TOO_LONG;
53 case bt::HostError::kCanceled:
54 return fble::PeripheralError::ABORTED;
55 default:
56 break;
57 }
58 return fble::PeripheralError::FAILED;
59 },
60 [](auto /*hci_error*/) { return fble::PeripheralError::FAILED; });
61 }
62
63 } // namespace
64
AdvertisementInstance(LowEnergyPeripheralServer * peripheral_server,AdvertisementInstanceId id,fuchsia::bluetooth::le::AdvertisingParameters parameters,fidl::InterfaceHandle<fuchsia::bluetooth::le::AdvertisedPeripheral> handle,AdvertiseCompleteCallback complete_cb)65 LowEnergyPeripheralServer::AdvertisementInstance::AdvertisementInstance(
66 LowEnergyPeripheralServer* peripheral_server,
67 AdvertisementInstanceId id,
68 fuchsia::bluetooth::le::AdvertisingParameters parameters,
69 fidl::InterfaceHandle<fuchsia::bluetooth::le::AdvertisedPeripheral> handle,
70 AdvertiseCompleteCallback complete_cb)
71 : peripheral_server_(peripheral_server),
72 id_(id),
73 parameters_(std::move(parameters)),
74 advertise_complete_cb_(std::move(complete_cb)),
75 weak_self_(this) {
76 PW_CHECK(advertise_complete_cb_);
77 advertised_peripheral_.Bind(std::move(handle));
78 advertised_peripheral_.set_error_handler(
79 [this, peripheral_server, id](zx_status_t /*status*/) {
80 CloseWith(fpromise::ok());
81 peripheral_server->RemoveAdvertisingInstance(id);
82 });
83 }
84
~AdvertisementInstance()85 LowEnergyPeripheralServer::AdvertisementInstance::~AdvertisementInstance() {
86 if (advertise_complete_cb_) {
87 CloseWith(fpromise::error(fble::PeripheralError::ABORTED));
88 }
89 }
90
StartAdvertising()91 void LowEnergyPeripheralServer::AdvertisementInstance::StartAdvertising() {
92 auto self = weak_self_.GetWeakPtr();
93 auto status_cb = [self](auto adv_instance, bt::hci::Result<> status) {
94 if (!self.is_alive()) {
95 bt_log(
96 DEBUG, LOG_TAG, "advertisement canceled before advertising started");
97 // Destroying `adv_instance` will stop advertising.
98 return;
99 }
100
101 if (bt_is_error(status,
102 WARN,
103 LOG_TAG,
104 "failed to start advertising (status: %s)",
105 bt_str(status))) {
106 self->CloseWith(fpromise::error(FidlErrorFromStatus(status)));
107 self->peripheral_server_->RemoveAdvertisingInstance(self->id_);
108 return;
109 }
110
111 self->Register(std::move(adv_instance));
112 };
113
114 peripheral_server_->StartAdvertisingInternal(
115 parameters_, std::move(status_cb), self->id_);
116 }
117
ListenL2cap(fble::ChannelListenerRegistryListenL2capRequest request,ListenL2capCallback callback)118 void LowEnergyPeripheralServer::ListenL2cap(
119 fble::ChannelListenerRegistryListenL2capRequest request,
120 ListenL2capCallback callback) {
121 // TODO(fxbug.dev/42178956): Implement ListenL2cap.
122 fble::ChannelListenerRegistry_ListenL2cap_Result result;
123 callback(std::move(result.set_err(ZX_ERR_NOT_SUPPORTED)));
124 }
125
Register(bt::gap::AdvertisementInstance instance)126 void LowEnergyPeripheralServer::AdvertisementInstance::Register(
127 bt::gap::AdvertisementInstance instance) {
128 PW_CHECK(!instance_);
129 instance_ = std::move(instance);
130 }
131
OnConnected(bt::gap::AdvertisementId advertisement_id,bt::gap::Adapter::LowEnergy::ConnectionResult result)132 void LowEnergyPeripheralServer::AdvertisementInstance::OnConnected(
133 bt::gap::AdvertisementId advertisement_id,
134 bt::gap::Adapter::LowEnergy::ConnectionResult result) {
135 PW_CHECK(advertisement_id != bt::gap::kInvalidAdvertisementId);
136
137 // HCI advertising ends when a connection is received (even for error
138 // results), so clear the stale advertisement handle.
139 instance_.reset();
140
141 if (result.is_error()) {
142 bt_log(INFO,
143 LOG_TAG,
144 "incoming connection failed; restarting advertising (adv instance "
145 "id: %zu, prev adv "
146 "id: %s)",
147 id_,
148 bt_str(advertisement_id));
149 StartAdvertising();
150 return;
151 }
152
153 std::unique_ptr<bt::gap::LowEnergyConnectionHandle> conn =
154 std::move(result).value();
155 bt::PeerId peer_id = conn->peer_identifier();
156 bt::gap::Peer* peer =
157 peripheral_server_->adapter()->peer_cache()->FindById(peer_id);
158 PW_CHECK(peer);
159
160 bt_log(INFO,
161 LOG_TAG,
162 "peripheral received connection to advertisement (peer: %s, adv id: "
163 "%s, adv "
164 "instance id: %zu)",
165 bt_str(peer->identifier()),
166 bt_str(advertisement_id),
167 id_);
168
169 fidl::InterfaceHandle<fble::Connection> conn_handle =
170 peripheral_server_->CreateConnectionServer(std::move(conn));
171
172 // Restart advertising after the client acknowledges the connection.
173 auto self = weak_self_.GetWeakPtr();
174 auto on_connected_cb = [self] {
175 if (self.is_alive()) {
176 self->StartAdvertising();
177 }
178 };
179 advertised_peripheral_->OnConnected(fidl_helpers::PeerToFidlLe(*peer),
180 std::move(conn_handle),
181 std::move(on_connected_cb));
182 }
183
CloseWith(fpromise::result<void,fuchsia::bluetooth::le::PeripheralError> result)184 void LowEnergyPeripheralServer::AdvertisementInstance::CloseWith(
185 fpromise::result<void, fuchsia::bluetooth::le::PeripheralError> result) {
186 if (advertise_complete_cb_) {
187 advertised_peripheral_.Unbind();
188 advertise_complete_cb_(std::move(result));
189 }
190 }
191
192 LowEnergyPeripheralServer::AdvertisementInstanceDeprecated::
AdvertisementInstanceDeprecated(fidl::InterfaceRequest<fuchsia::bluetooth::le::AdvertisingHandle> handle)193 AdvertisementInstanceDeprecated(
194 fidl::InterfaceRequest<fuchsia::bluetooth::le::AdvertisingHandle>
195 handle)
196 : handle_(std::move(handle)) {
197 PW_DCHECK(handle_);
198 }
199
200 LowEnergyPeripheralServer::AdvertisementInstanceDeprecated::
~AdvertisementInstanceDeprecated()201 ~AdvertisementInstanceDeprecated() {
202 handle_closed_wait_.Cancel();
203 }
204
205 zx_status_t
Register(bt::gap::AdvertisementInstance instance)206 LowEnergyPeripheralServer::AdvertisementInstanceDeprecated::Register(
207 bt::gap::AdvertisementInstance instance) {
208 PW_DCHECK(!instance_);
209
210 instance_ = std::move(instance);
211
212 handle_closed_wait_.set_object(handle_.channel().get());
213 handle_closed_wait_.set_trigger(ZX_CHANNEL_PEER_CLOSED);
214 handle_closed_wait_.set_handler(
215 [this](auto*, auto*, zx_status_t status, const auto*) {
216 // Don't do anything if the wait was explicitly canceled by us.
217 if (status != ZX_ERR_CANCELED) {
218 bt_log(TRACE, LOG_TAG, "AdvertisingHandle closed");
219 instance_.reset();
220 }
221 });
222
223 zx_status_t status =
224 handle_closed_wait_.Begin(async_get_default_dispatcher());
225 if (status != ZX_OK) {
226 bt_log(DEBUG,
227 LOG_TAG,
228 "failed to begin wait on AdvertisingHandle: %s",
229 zx_status_get_string(status));
230 }
231 return status;
232 }
233
LowEnergyPeripheralServer(bt::gap::Adapter::WeakPtr adapter,bt::gatt::GATT::WeakPtr gatt,fidl::InterfaceRequest<Peripheral> request,bool privileged)234 LowEnergyPeripheralServer::LowEnergyPeripheralServer(
235 bt::gap::Adapter::WeakPtr adapter,
236 bt::gatt::GATT::WeakPtr gatt,
237 fidl::InterfaceRequest<Peripheral> request,
238 bool privileged)
239 : AdapterServerBase(std::move(adapter), this, std::move(request)),
240 gatt_(std::move(gatt)),
241 privileged_(privileged),
242 weak_self_(this) {}
243
~LowEnergyPeripheralServer()244 LowEnergyPeripheralServer::~LowEnergyPeripheralServer() {
245 PW_CHECK(adapter()->bredr());
246 }
247
Advertise(fble::AdvertisingParameters parameters,fidl::InterfaceHandle<fuchsia::bluetooth::le::AdvertisedPeripheral> advertised_peripheral,AdvertiseCallback callback)248 void LowEnergyPeripheralServer::Advertise(
249 fble::AdvertisingParameters parameters,
250 fidl::InterfaceHandle<fuchsia::bluetooth::le::AdvertisedPeripheral>
251 advertised_peripheral,
252 AdvertiseCallback callback) {
253 // Advertise and StartAdvertising may not be used simultaneously.
254 if (advertisement_deprecated_.has_value()) {
255 callback(fpromise::error(fble::PeripheralError::FAILED));
256 return;
257 }
258
259 // TODO: https://fxbug.dev/42156474 - As a temporary hack until multiple
260 // advertisements is supported, don't allow more than one advertisement. The
261 // current behavior of hci::LegacyLowEnergyAdvertiser is to replace the
262 // current advertisement, which is not the intended behavior of `Advertise`.
263 // NOTE: This is insufficient when there are multiple Peripheral clients
264 // advertising, but that is the status quo with `StartAdvertising` anyway (the
265 // last advertiser wins).
266 if (!advertisements_.empty()) {
267 callback(fpromise::error(fble::PeripheralError::FAILED));
268 return;
269 }
270
271 AdvertisementInstanceId instance_id = next_advertisement_instance_id_++;
272
273 // Non-privileged clients should not be able to advertise with a public
274 // address, so we default to a random address type.
275 if (!privileged_ && parameters.has_address_type() &&
276 parameters.address_type() == fuchsia::bluetooth::AddressType::PUBLIC) {
277 bt_log(WARN,
278 LOG_TAG,
279 "Cannot advertise public address (instance id: %zu)",
280 instance_id);
281 callback(fpromise::error(fble::PeripheralError::INVALID_PARAMETERS));
282 return;
283 }
284
285 auto [iter, inserted] =
286 advertisements_.try_emplace(instance_id,
287 this,
288 instance_id,
289 std::move(parameters),
290 std::move(advertised_peripheral),
291 std::move(callback));
292 PW_CHECK(inserted);
293 iter->second.StartAdvertising();
294 }
295
StartAdvertising(fble::AdvertisingParameters parameters,::fidl::InterfaceRequest<fble::AdvertisingHandle> token,StartAdvertisingCallback callback)296 void LowEnergyPeripheralServer::StartAdvertising(
297 fble::AdvertisingParameters parameters,
298 ::fidl::InterfaceRequest<fble::AdvertisingHandle> token,
299 StartAdvertisingCallback callback) {
300 fble::Peripheral_StartAdvertising_Result result;
301
302 // Advertise and StartAdvertising may not be used simultaneously.
303 if (!advertisements_.empty()) {
304 result.set_err(fble::PeripheralError::INVALID_PARAMETERS);
305 callback(std::move(result));
306 return;
307 }
308
309 if (!token) {
310 result.set_err(fble::PeripheralError::INVALID_PARAMETERS);
311 callback(std::move(result));
312 return;
313 }
314
315 if (advertisement_deprecated_) {
316 bt_log(DEBUG, LOG_TAG, "reconfigure existing advertising instance");
317 advertisement_deprecated_.reset();
318 }
319
320 // Create an entry to mark that the request is in progress.
321 advertisement_deprecated_.emplace(std::move(token));
322
323 auto self = weak_self_.GetWeakPtr();
324 auto status_cb = [self, callback = std::move(callback), func = __FUNCTION__](
325 auto instance, bt::hci::Result<> status) {
326 // Advertising will be stopped when |instance| gets destroyed.
327 if (!self.is_alive()) {
328 return;
329 }
330
331 PW_CHECK(self->advertisement_deprecated_);
332 PW_CHECK(self->advertisement_deprecated_->id() ==
333 bt::gap::kInvalidAdvertisementId);
334
335 fble::Peripheral_StartAdvertising_Result result;
336 if (status.is_error()) {
337 bt_log(WARN,
338 LOG_TAG,
339 "%s: failed to start advertising (status: %s)",
340 func,
341 bt_str(status));
342
343 result.set_err(FidlErrorFromStatus(status));
344
345 // The only scenario in which it is valid to leave |advertisement_| intact
346 // in a failure scenario is if StartAdvertising was called while a
347 // previous call was in progress. This aborts the prior request causing it
348 // to end with the "kCanceled" status. This means that another request is
349 // currently progress.
350 if (!status.error_value().is(bt::HostError::kCanceled)) {
351 self->advertisement_deprecated_.reset();
352 }
353
354 callback(std::move(result));
355 return;
356 }
357
358 zx_status_t ecode =
359 self->advertisement_deprecated_->Register(std::move(instance));
360 if (ecode != ZX_OK) {
361 result.set_err(fble::PeripheralError::FAILED);
362 self->advertisement_deprecated_.reset();
363 callback(std::move(result));
364 return;
365 }
366
367 result.set_response({});
368 callback(std::move(result));
369 };
370
371 StartAdvertisingInternal(parameters, std::move(status_cb));
372 }
373
374 const bt::gap::LowEnergyConnectionHandle*
FindConnectionForTesting(bt::PeerId id) const375 LowEnergyPeripheralServer::FindConnectionForTesting(bt::PeerId id) const {
376 auto connections_iter = std::find_if(
377 connections_.begin(), connections_.end(), [id](const auto& conn) {
378 return conn.second->conn()->peer_identifier() == id;
379 });
380 if (connections_iter != connections_.end()) {
381 return connections_iter->second->conn();
382 }
383 return nullptr;
384 }
385
OnConnectedDeprecated(bt::gap::AdvertisementId advertisement_id,bt::gap::Adapter::LowEnergy::ConnectionResult result)386 void LowEnergyPeripheralServer::OnConnectedDeprecated(
387 bt::gap::AdvertisementId advertisement_id,
388 bt::gap::Adapter::LowEnergy::ConnectionResult result) {
389 PW_CHECK(advertisement_id != bt::gap::kInvalidAdvertisementId);
390
391 // Abort connection procedure if advertisement was canceled by the client.
392 if (!advertisement_deprecated_ ||
393 advertisement_deprecated_->id() != advertisement_id) {
394 bt_log(
395 INFO,
396 LOG_TAG,
397 "dropping connection to canceled advertisement (advertisement id: %s)",
398 bt_str(advertisement_id));
399 return;
400 }
401
402 zx::channel local, remote;
403 zx_status_t status = zx::channel::create(0, &local, &remote);
404 if (status != ZX_OK) {
405 bt_log(ERROR,
406 LOG_TAG,
407 "failed to create channel for Connection (status: %s)",
408 zx_status_get_string(status));
409 return;
410 }
411
412 if (result.is_error()) {
413 bt_log(INFO,
414 LOG_TAG,
415 "incoming connection to advertisement failed (advertisement id: %s)",
416 bt_str(advertisement_id));
417 return;
418 }
419
420 auto conn = std::move(result).value();
421 auto peer_id = conn->peer_identifier();
422 auto* peer = adapter()->peer_cache()->FindById(peer_id);
423 PW_CHECK(peer);
424
425 bt_log(INFO,
426 LOG_TAG,
427 "central connected (peer: %s, advertisement id: %s)",
428 bt_str(peer->identifier()),
429 bt_str(advertisement_id));
430
431 fidl::InterfaceHandle<fble::Connection> conn_handle =
432 CreateConnectionServer(std::move(conn));
433
434 binding()->events().OnPeerConnected(fidl_helpers::PeerToFidlLe(*peer),
435 std::move(conn_handle));
436 advertisement_deprecated_.reset();
437 }
438
439 fidl::InterfaceHandle<fuchsia::bluetooth::le::Connection>
CreateConnectionServer(std::unique_ptr<bt::gap::LowEnergyConnectionHandle> connection)440 LowEnergyPeripheralServer::CreateConnectionServer(
441 std::unique_ptr<bt::gap::LowEnergyConnectionHandle> connection) {
442 zx::channel local, remote;
443 zx_status_t status = zx::channel::create(0, &local, &remote);
444 PW_CHECK(status == ZX_OK);
445
446 auto conn_server_id = next_connection_server_id_++;
447 auto conn_server = std::make_unique<LowEnergyConnectionServer>(
448 adapter(),
449 gatt_,
450 std::move(connection),
451 std::move(local),
452 [this, conn_server_id] {
453 bt_log(INFO, LOG_TAG, "connection closed");
454 connections_.erase(conn_server_id);
455 });
456 connections_[conn_server_id] = std::move(conn_server);
457
458 return fidl::InterfaceHandle<fble::Connection>(std::move(remote));
459 }
460
StartAdvertisingInternal(fuchsia::bluetooth::le::AdvertisingParameters & parameters,bt::gap::Adapter::LowEnergy::AdvertisingStatusCallback status_cb,std::optional<AdvertisementInstanceId> advertisement_instance)461 void LowEnergyPeripheralServer::StartAdvertisingInternal(
462 fuchsia::bluetooth::le::AdvertisingParameters& parameters,
463 bt::gap::Adapter::LowEnergy::AdvertisingStatusCallback status_cb,
464 std::optional<AdvertisementInstanceId> advertisement_instance) {
465 bt::AdvertisingData adv_data;
466 bool include_tx_power_level = false;
467 if (parameters.has_data()) {
468 auto maybe_adv_data =
469 fidl_helpers::AdvertisingDataFromFidl(parameters.data());
470 if (!maybe_adv_data) {
471 bt_log(WARN, LOG_TAG, "invalid advertising data");
472 status_cb({}, ToResult(bt::HostError::kInvalidParameters));
473 return;
474 }
475
476 adv_data = std::move(*maybe_adv_data);
477 if (parameters.data().has_include_tx_power_level() &&
478 parameters.data().include_tx_power_level()) {
479 bt_log(TRACE,
480 LOG_TAG,
481 "Including TX Power level in advertising data at HCI layer");
482 include_tx_power_level = true;
483 }
484 }
485
486 bt::AdvertisingData scan_rsp;
487 if (parameters.has_scan_response()) {
488 auto maybe_scan_rsp =
489 fidl_helpers::AdvertisingDataFromFidl(parameters.scan_response());
490 if (!maybe_scan_rsp) {
491 bt_log(WARN, LOG_TAG, "invalid scan response in advertising data");
492 status_cb({}, ToResult(bt::HostError::kInvalidParameters));
493 return;
494 }
495 scan_rsp = std::move(*maybe_scan_rsp);
496 }
497
498 fble::AdvertisingModeHint mode_hint = fble::AdvertisingModeHint::SLOW;
499 if (parameters.has_mode_hint()) {
500 mode_hint = parameters.mode_hint();
501 }
502 bt::gap::AdvertisingInterval interval =
503 fidl_helpers::AdvertisingIntervalFromFidl(mode_hint);
504
505 std::optional<bt::gap::Adapter::LowEnergy::ConnectableAdvertisingParameters>
506 connectable_params;
507
508 // Per the API contract of `AdvertisingParameters` FIDL, if
509 // `connection_options` is present or the deprecated `connectable` parameter
510 // is true, advertisements will be connectable. `connectable_parameter` was
511 // the predecessor of `connection_options` and
512 // TODO: https://fxbug.dev/42121197 - will be removed once all consumers of it
513 // have migrated to `connection_options`.
514 bool connectable = parameters.has_connection_options() ||
515 (parameters.has_connectable() && parameters.connectable());
516 if (connectable) {
517 connectable_params.emplace();
518
519 auto self = weak_self_.GetWeakPtr();
520 connectable_params->connection_cb =
521 [self, advertisement_instance](
522 bt::gap::AdvertisementId advertisement_id,
523 bt::gap::Adapter::LowEnergy::ConnectionResult result) {
524 if (!self.is_alive()) {
525 return;
526 }
527
528 // Handle connection for deprecated StartAdvertising method.
529 if (!advertisement_instance) {
530 self->OnConnectedDeprecated(advertisement_id, std::move(result));
531 return;
532 }
533
534 auto advertisement_iter =
535 self->advertisements_.find(*advertisement_instance);
536 if (advertisement_iter == self->advertisements_.end()) {
537 if (result.is_ok()) {
538 bt_log(DEBUG,
539 LOG_TAG,
540 "releasing connection handle for canceled advertisement "
541 "(peer: %s)",
542 bt_str(result.value()->peer_identifier()));
543 result.value()->Release();
544 }
545 return;
546 }
547 advertisement_iter->second.OnConnected(advertisement_id,
548 std::move(result));
549 };
550
551 // Per the API contract of the `ConnectionOptions` FIDL, the bondable mode
552 // of the connection defaults to bondable mode unless the
553 // `connection_options` table exists and `bondable_mode` is explicitly set
554 // to false.
555 connectable_params->bondable_mode =
556 (!parameters.has_connection_options() ||
557 !parameters.connection_options().has_bondable_mode() ||
558 parameters.connection_options().bondable_mode())
559 ? BondableMode::Bondable
560 : BondableMode::NonBondable;
561 }
562
563 bool extended_pdu = false;
564 if (parameters.has_advertising_procedure()) {
565 extended_pdu = parameters.advertising_procedure().is_extended();
566 }
567
568 std::optional<bt::DeviceAddress::Type> address_type = std::nullopt;
569 if (parameters.has_address_type()) {
570 address_type =
571 fidl_helpers::FidlToDeviceAddressType(parameters.address_type());
572 }
573
574 PW_CHECK(adapter()->le());
575 adapter()->le()->StartAdvertising(std::move(adv_data),
576 std::move(scan_rsp),
577 interval,
578 extended_pdu,
579 /*anonymous=*/false,
580 include_tx_power_level,
581 std::move(connectable_params),
582 address_type,
583 std::move(status_cb));
584 }
585
LowEnergyPrivilegedPeripheralServer(const bt::gap::Adapter::WeakPtr & adapter,bt::gatt::GATT::WeakPtr gatt,fidl::InterfaceRequest<fuchsia::bluetooth::le::PrivilegedPeripheral> request)586 LowEnergyPrivilegedPeripheralServer::LowEnergyPrivilegedPeripheralServer(
587 const bt::gap::Adapter::WeakPtr& adapter,
588 bt::gatt::GATT::WeakPtr gatt,
589 fidl::InterfaceRequest<fuchsia::bluetooth::le::PrivilegedPeripheral>
590 request)
591 : AdapterServerBase(adapter, this, std::move(request)), weak_self_(this) {
592 fidl::InterfaceHandle<fuchsia::bluetooth::le::Peripheral> handle;
593 le_peripheral_server_ = std::make_unique<LowEnergyPeripheralServer>(
594 adapter, std::move(gatt), handle.NewRequest(), /*privileged=*/true);
595 }
596
Advertise(fuchsia::bluetooth::le::AdvertisingParameters parameters,fidl::InterfaceHandle<fuchsia::bluetooth::le::AdvertisedPeripheral> advertised_peripheral,AdvertiseCallback callback)597 void LowEnergyPrivilegedPeripheralServer::Advertise(
598 fuchsia::bluetooth::le::AdvertisingParameters parameters,
599 fidl::InterfaceHandle<fuchsia::bluetooth::le::AdvertisedPeripheral>
600 advertised_peripheral,
601 AdvertiseCallback callback) {
602 le_peripheral_server_->Advertise(std::move(parameters),
603 std::move(advertised_peripheral),
604 std::move(callback));
605 }
606
StartAdvertising(fble::AdvertisingParameters parameters,::fidl::InterfaceRequest<fble::AdvertisingHandle> token,StartAdvertisingCallback callback)607 void LowEnergyPrivilegedPeripheralServer::StartAdvertising(
608 fble::AdvertisingParameters parameters,
609 ::fidl::InterfaceRequest<fble::AdvertisingHandle> token,
610 StartAdvertisingCallback callback) {
611 le_peripheral_server_->StartAdvertising(
612 std::move(parameters), std::move(token), std::move(callback));
613 }
614
ListenL2cap(fble::ChannelListenerRegistryListenL2capRequest request,ListenL2capCallback callback)615 void LowEnergyPrivilegedPeripheralServer::ListenL2cap(
616 fble::ChannelListenerRegistryListenL2capRequest request,
617 ListenL2capCallback callback) {
618 le_peripheral_server_->ListenL2cap(std::move(request), std::move(callback));
619 }
620
621 } // namespace bthost
622