1 /*
2  * Copyright 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "hci/acl_manager.h"
18 
19 #include <bluetooth/log.h>
20 
21 #include <atomic>
22 #include <future>
23 #include <mutex>
24 
25 #include "common/bidi_queue.h"
26 #include "common/byte_array.h"
27 #include "dumpsys_data_generated.h"
28 #include "hci/acl_manager/acl_scheduler.h"
29 #include "hci/acl_manager/classic_impl.h"
30 #include "hci/acl_manager/le_acceptlist_callbacks.h"
31 #include "hci/acl_manager/le_acl_connection.h"
32 #include "hci/acl_manager/le_impl.h"
33 #include "hci/acl_manager/round_robin_scheduler.h"
34 #include "hci/controller.h"
35 #include "hci/hci_layer.h"
36 #include "hci/remote_name_request.h"
37 #include "hci_acl_manager_generated.h"
38 #include "security/security_module.h"
39 #include "storage/config_keys.h"
40 #include "storage/storage_module.h"
41 
42 namespace bluetooth {
43 namespace hci {
44 
45 constexpr uint16_t kQualcommDebugHandle = 0xedc;
46 
47 using acl_manager::AclConnection;
48 using common::Bind;
49 using common::BindOnce;
50 
51 using acl_manager::classic_impl;
52 using acl_manager::ClassicAclConnection;
53 using acl_manager::ConnectionCallbacks;
54 
55 using acl_manager::le_impl;
56 using acl_manager::LeAcceptlistCallbacks;
57 using acl_manager::LeAclConnection;
58 using acl_manager::LeConnectionCallbacks;
59 
60 using acl_manager::RoundRobinScheduler;
61 
62 using acl_manager::AclScheduler;
63 
64 struct AclManager::impl {
implbluetooth::hci::AclManager::impl65   impl(const AclManager& acl_manager) : acl_manager_(acl_manager) {}
66 
Startbluetooth::hci::AclManager::impl67   void Start() {
68     hci_layer_ = acl_manager_.GetDependency<HciLayer>();
69     handler_ = acl_manager_.GetHandler();
70     controller_ = acl_manager_.GetDependency<Controller>();
71     round_robin_scheduler_ = new RoundRobinScheduler(handler_, controller_, hci_layer_->GetAclQueueEnd());
72     acl_scheduler_ = acl_manager_.GetDependency<AclScheduler>();
73 
74     remote_name_request_module_ = acl_manager_.GetDependency<RemoteNameRequestModule>();
75 
76     bool crash_on_unknown_handle = false;
77     {
78       const std::lock_guard<std::mutex> lock(dumpsys_mutex_);
79       classic_impl_ = new classic_impl(
80           hci_layer_,
81           controller_,
82           handler_,
83           round_robin_scheduler_,
84           crash_on_unknown_handle,
85           acl_scheduler_,
86           remote_name_request_module_);
87       le_impl_ = new le_impl(hci_layer_, controller_, handler_, round_robin_scheduler_, crash_on_unknown_handle);
88     }
89 
90     hci_queue_end_ = hci_layer_->GetAclQueueEnd();
91     hci_queue_end_->RegisterDequeue(
92         handler_, common::Bind(&impl::dequeue_and_route_acl_packet_to_connection, common::Unretained(this)));
93   }
94 
Stopbluetooth::hci::AclManager::impl95   void Stop() {
96     hci_queue_end_->UnregisterDequeue();
97     if (enqueue_registered_.exchange(false)) {
98       hci_queue_end_->UnregisterEnqueue();
99     }
100 
101     {
102       const std::lock_guard<std::mutex> lock(dumpsys_mutex_);
103       delete le_impl_;
104       delete classic_impl_;
105       le_impl_ = nullptr;
106       classic_impl_ = nullptr;
107     }
108 
109     unknown_acl_alarm_.reset();
110     waiting_packets_.clear();
111 
112     delete round_robin_scheduler_;
113     hci_queue_end_ = nullptr;
114     handler_ = nullptr;
115     hci_layer_ = nullptr;
116     acl_scheduler_ = nullptr;
117   }
118 
retry_unknown_aclbluetooth::hci::AclManager::impl119   void retry_unknown_acl(bool timed_out) {
120     std::vector<AclView> unsent_packets;
121     for (const auto& itr : waiting_packets_) {
122       auto handle = itr.GetHandle();
123       if (!classic_impl_->send_packet_upward(
124               handle,
125               [itr](struct acl_manager::assembler* assembler) {
126                 assembler->on_incoming_packet(itr);
127               }) &&
128           !le_impl_->send_packet_upward(handle, [itr](struct acl_manager::assembler* assembler) {
129             assembler->on_incoming_packet(itr);
130           })) {
131         if (!timed_out) {
132           unsent_packets.push_back(itr);
133         } else {
134           log::error(
135               "Dropping packet of size {} to unknown connection 0x{:x}",
136               itr.size(),
137               itr.GetHandle());
138         }
139       }
140     }
141     waiting_packets_ = std::move(unsent_packets);
142   }
143 
on_unknown_acl_timerbluetooth::hci::AclManager::impl144   static void on_unknown_acl_timer(struct AclManager::impl* impl) {
145     log::info("Timer fired!");
146     impl->retry_unknown_acl(/* timed_out = */ true);
147     impl->unknown_acl_alarm_.reset();
148   }
149 
150   // Invoked from some external Queue Reactable context 2
dequeue_and_route_acl_packet_to_connectionbluetooth::hci::AclManager::impl151   void dequeue_and_route_acl_packet_to_connection() {
152     // Retry any waiting packets first
153     if (!waiting_packets_.empty()) {
154       retry_unknown_acl(/* timed_out = */ false);
155     }
156 
157     auto packet = hci_queue_end_->TryDequeue();
158     log::assert_that(packet != nullptr, "assert failed: packet != nullptr");
159     if (!packet->IsValid()) {
160       log::info("Dropping invalid packet of size {}", packet->size());
161       return;
162     }
163     uint16_t handle = packet->GetHandle();
164     if (handle == kQualcommDebugHandle) return;
165     if (classic_impl_->send_packet_upward(
166             handle, [&packet](struct acl_manager::assembler* assembler) { assembler->on_incoming_packet(*packet); }))
167       return;
168     if (le_impl_->send_packet_upward(
169             handle, [&packet](struct acl_manager::assembler* assembler) { assembler->on_incoming_packet(*packet); }))
170       return;
171     if (unknown_acl_alarm_ == nullptr) {
172       unknown_acl_alarm_.reset(new os::Alarm(handler_));
173     }
174     waiting_packets_.push_back(*packet);
175     log::info(
176         "Saving packet of size {} to unknown connection 0x{:x}",
177         packet->size(),
178         packet->GetHandle());
179     unknown_acl_alarm_->Schedule(
180         BindOnce(&on_unknown_acl_timer, common::Unretained(this)), kWaitBeforeDroppingUnknownAcl);
181   }
182 
183   void Dump(
184       std::promise<flatbuffers::Offset<AclManagerData>> promise, flatbuffers::FlatBufferBuilder* fb_builder) const;
185 
186   const AclManager& acl_manager_;
187 
188   classic_impl* classic_impl_ = nullptr;
189   le_impl* le_impl_ = nullptr;
190   AclScheduler* acl_scheduler_ = nullptr;
191   RemoteNameRequestModule* remote_name_request_module_ = nullptr;
192   os::Handler* handler_ = nullptr;
193   Controller* controller_ = nullptr;
194   HciLayer* hci_layer_ = nullptr;
195   RoundRobinScheduler* round_robin_scheduler_ = nullptr;
196   common::BidiQueueEnd<AclBuilder, AclView>* hci_queue_end_ = nullptr;
197   std::atomic_bool enqueue_registered_ = false;
198   uint16_t default_link_policy_settings_ = 0xffff;
199   mutable std::mutex dumpsys_mutex_;
200   std::unique_ptr<os::Alarm> unknown_acl_alarm_;
201   std::vector<AclView> waiting_packets_;
202   static constexpr std::chrono::seconds kWaitBeforeDroppingUnknownAcl{1};
203 };
204 
AclManager()205 AclManager::AclManager() : pimpl_(std::make_unique<impl>(*this)) {}
206 
RegisterCallbacks(ConnectionCallbacks * callbacks,os::Handler * handler)207 void AclManager::RegisterCallbacks(ConnectionCallbacks* callbacks, os::Handler* handler) {
208   log::assert_that(
209       callbacks != nullptr && handler != nullptr,
210       "assert failed: callbacks != nullptr && handler != nullptr");
211   GetHandler()->Post(common::BindOnce(
212       &classic_impl::handle_register_callbacks,
213       common::Unretained(pimpl_->classic_impl_),
214       common::Unretained(callbacks),
215       common::Unretained(handler)));
216 }
217 
UnregisterCallbacks(ConnectionCallbacks * callbacks,std::promise<void> promise)218 void AclManager::UnregisterCallbacks(ConnectionCallbacks* callbacks, std::promise<void> promise) {
219   log::assert_that(callbacks != nullptr, "assert failed: callbacks != nullptr");
220   CallOn(
221       pimpl_->classic_impl_,
222       &classic_impl::handle_unregister_callbacks,
223       common::Unretained(callbacks),
224       std::move(promise));
225 }
226 
RegisterLeCallbacks(LeConnectionCallbacks * callbacks,os::Handler * handler)227 void AclManager::RegisterLeCallbacks(LeConnectionCallbacks* callbacks, os::Handler* handler) {
228   log::assert_that(
229       callbacks != nullptr && handler != nullptr,
230       "assert failed: callbacks != nullptr && handler != nullptr");
231   CallOn(
232       pimpl_->le_impl_,
233       &le_impl::handle_register_le_callbacks,
234       common::Unretained(callbacks),
235       common::Unretained(handler));
236 }
237 
RegisterLeAcceptlistCallbacks(LeAcceptlistCallbacks * callbacks)238 void AclManager::RegisterLeAcceptlistCallbacks(LeAcceptlistCallbacks* callbacks) {
239   log::assert_that(callbacks != nullptr, "assert failed: callbacks != nullptr");
240   CallOn(
241       pimpl_->le_impl_,
242       &le_impl::handle_register_le_acceptlist_callbacks,
243       common::Unretained(callbacks));
244 }
245 
UnregisterLeCallbacks(LeConnectionCallbacks * callbacks,std::promise<void> promise)246 void AclManager::UnregisterLeCallbacks(LeConnectionCallbacks* callbacks, std::promise<void> promise) {
247   log::assert_that(callbacks != nullptr, "assert failed: callbacks != nullptr");
248   CallOn(pimpl_->le_impl_, &le_impl::handle_unregister_le_callbacks, common::Unretained(callbacks), std::move(promise));
249 }
250 
UnregisterLeAcceptlistCallbacks(LeAcceptlistCallbacks * callbacks,std::promise<void> promise)251 void AclManager::UnregisterLeAcceptlistCallbacks(
252     LeAcceptlistCallbacks* callbacks, std::promise<void> promise) {
253   log::assert_that(callbacks != nullptr, "assert failed: callbacks != nullptr");
254   CallOn(
255       pimpl_->le_impl_,
256       &le_impl::handle_unregister_le_acceptlist_callbacks,
257       common::Unretained(callbacks),
258       std::move(promise));
259 }
260 
CreateConnection(Address address)261 void AclManager::CreateConnection(Address address) {
262   CallOn(pimpl_->classic_impl_, &classic_impl::create_connection, address);
263 }
264 
CreateLeConnection(AddressWithType address_with_type,bool is_direct)265 void AclManager::CreateLeConnection(AddressWithType address_with_type, bool is_direct) {
266   if (!is_direct) {
267     CallOn(pimpl_->le_impl_, &le_impl::add_device_to_background_connection_list, address_with_type);
268   }
269   CallOn(pimpl_->le_impl_, &le_impl::create_le_connection, address_with_type, true, is_direct);
270 }
271 
IsOnBackgroundList(AddressWithType address_with_type,std::promise<bool> promise)272 void AclManager::IsOnBackgroundList(AddressWithType address_with_type, std::promise<bool> promise) {
273   CallOn(pimpl_->le_impl_, &le_impl::is_on_background_connection_list, address_with_type, std::move(promise));
274 }
275 
SetLeSuggestedDefaultDataParameters(uint16_t octets,uint16_t time)276 void AclManager::SetLeSuggestedDefaultDataParameters(uint16_t octets, uint16_t time) {
277   CallOn(pimpl_->le_impl_, &le_impl::set_le_suggested_default_data_parameters, octets, time);
278 }
279 
LeSetDefaultSubrate(uint16_t subrate_min,uint16_t subrate_max,uint16_t max_latency,uint16_t cont_num,uint16_t sup_tout)280 void AclManager::LeSetDefaultSubrate(
281     uint16_t subrate_min, uint16_t subrate_max, uint16_t max_latency, uint16_t cont_num, uint16_t sup_tout) {
282   CallOn(pimpl_->le_impl_, &le_impl::LeSetDefaultSubrate, subrate_min, subrate_max, max_latency, cont_num, sup_tout);
283 }
284 
SetPrivacyPolicyForInitiatorAddress(LeAddressManager::AddressPolicy address_policy,AddressWithType fixed_address,std::chrono::milliseconds minimum_rotation_time,std::chrono::milliseconds maximum_rotation_time)285 void AclManager::SetPrivacyPolicyForInitiatorAddress(
286     LeAddressManager::AddressPolicy address_policy,
287     AddressWithType fixed_address,
288     std::chrono::milliseconds minimum_rotation_time,
289     std::chrono::milliseconds maximum_rotation_time) {
290   Octet16 rotation_irk{};
291   auto irk_prop = GetDependency<storage::StorageModule>()->GetProperty(
292       BTIF_STORAGE_SECTION_ADAPTER, BTIF_STORAGE_KEY_LE_LOCAL_KEY_IRK);
293   if (irk_prop.has_value()) {
294     auto irk = common::ByteArray<16>::FromString(irk_prop.value());
295     if (irk.has_value()) {
296       rotation_irk = irk->bytes;
297     }
298   }
299   CallOn(
300       pimpl_->le_impl_,
301       &le_impl::set_privacy_policy_for_initiator_address,
302       address_policy,
303       fixed_address,
304       rotation_irk,
305       minimum_rotation_time,
306       maximum_rotation_time);
307 }
308 
309 // TODO(jpawlowski): remove once we have config file abstraction in cert tests
SetPrivacyPolicyForInitiatorAddressForTest(LeAddressManager::AddressPolicy address_policy,AddressWithType fixed_address,Octet16 rotation_irk,std::chrono::milliseconds minimum_rotation_time,std::chrono::milliseconds maximum_rotation_time)310 void AclManager::SetPrivacyPolicyForInitiatorAddressForTest(
311     LeAddressManager::AddressPolicy address_policy,
312     AddressWithType fixed_address,
313     Octet16 rotation_irk,
314     std::chrono::milliseconds minimum_rotation_time,
315     std::chrono::milliseconds maximum_rotation_time) {
316   CallOn(
317       pimpl_->le_impl_,
318       &le_impl::set_privacy_policy_for_initiator_address_for_test,
319       address_policy,
320       fixed_address,
321       rotation_irk,
322       minimum_rotation_time,
323       maximum_rotation_time);
324 }
325 
CancelConnect(Address address)326 void AclManager::CancelConnect(Address address) {
327   CallOn(pimpl_->classic_impl_, &classic_impl::cancel_connect, address);
328 }
329 
CancelLeConnect(AddressWithType address_with_type)330 void AclManager::CancelLeConnect(AddressWithType address_with_type) {
331   CallOn(pimpl_->le_impl_, &le_impl::remove_device_from_background_connection_list, address_with_type);
332   CallOn(pimpl_->le_impl_, &le_impl::cancel_connect, address_with_type);
333 }
334 
RemoveFromBackgroundList(AddressWithType address_with_type)335 void AclManager::RemoveFromBackgroundList(AddressWithType address_with_type) {
336   CallOn(pimpl_->le_impl_, &le_impl::remove_device_from_background_connection_list, address_with_type);
337 }
338 
ClearFilterAcceptList()339 void AclManager::ClearFilterAcceptList() {
340   CallOn(pimpl_->le_impl_, &le_impl::clear_filter_accept_list);
341 }
342 
AddDeviceToResolvingList(AddressWithType address_with_type,const std::array<uint8_t,16> & peer_irk,const std::array<uint8_t,16> & local_irk)343 void AclManager::AddDeviceToResolvingList(
344     AddressWithType address_with_type,
345     const std::array<uint8_t, 16>& peer_irk,
346     const std::array<uint8_t, 16>& local_irk) {
347   CallOn(pimpl_->le_impl_, &le_impl::add_device_to_resolving_list, address_with_type, peer_irk, local_irk);
348 }
349 
RemoveDeviceFromResolvingList(AddressWithType address_with_type)350 void AclManager::RemoveDeviceFromResolvingList(AddressWithType address_with_type) {
351   CallOn(pimpl_->le_impl_, &le_impl::remove_device_from_resolving_list, address_with_type);
352 }
353 
ClearResolvingList()354 void AclManager::ClearResolvingList() {
355   CallOn(pimpl_->le_impl_, &le_impl::clear_resolving_list);
356 }
357 
CentralLinkKey(KeyFlag key_flag)358 void AclManager::CentralLinkKey(KeyFlag key_flag) {
359   CallOn(pimpl_->classic_impl_, &classic_impl::central_link_key, key_flag);
360 }
361 
SwitchRole(Address address,Role role)362 void AclManager::SwitchRole(Address address, Role role) {
363   CallOn(pimpl_->classic_impl_, &classic_impl::switch_role, address, role);
364 }
365 
ReadDefaultLinkPolicySettings()366 uint16_t AclManager::ReadDefaultLinkPolicySettings() {
367   log::assert_that(pimpl_->default_link_policy_settings_ != 0xffff, "Settings were never written");
368   return pimpl_->default_link_policy_settings_;
369 }
370 
WriteDefaultLinkPolicySettings(uint16_t default_link_policy_settings)371 void AclManager::WriteDefaultLinkPolicySettings(uint16_t default_link_policy_settings) {
372   pimpl_->default_link_policy_settings_ = default_link_policy_settings;
373   CallOn(pimpl_->classic_impl_, &classic_impl::write_default_link_policy_settings, default_link_policy_settings);
374 }
375 
OnAdvertisingSetTerminated(ErrorCode status,uint16_t conn_handle,uint8_t adv_set_id,hci::AddressWithType adv_address,bool is_discoverable)376 void AclManager::OnAdvertisingSetTerminated(
377     ErrorCode status,
378     uint16_t conn_handle,
379     uint8_t adv_set_id,
380     hci::AddressWithType adv_address,
381     bool is_discoverable) {
382   if (status == ErrorCode::SUCCESS) {
383     CallOn(
384         pimpl_->le_impl_,
385         &le_impl::OnAdvertisingSetTerminated,
386         conn_handle,
387         adv_set_id,
388         adv_address,
389         is_discoverable);
390   }
391 }
392 
OnClassicSuspendInitiatedDisconnect(uint16_t handle,ErrorCode reason)393 void AclManager::OnClassicSuspendInitiatedDisconnect(uint16_t handle, ErrorCode reason) {
394   CallOn(pimpl_->classic_impl_, &classic_impl::on_classic_disconnect, handle, reason);
395 }
396 
OnLeSuspendInitiatedDisconnect(uint16_t handle,ErrorCode reason)397 void AclManager::OnLeSuspendInitiatedDisconnect(uint16_t handle, ErrorCode reason) {
398   CallOn(pimpl_->le_impl_, &le_impl::on_le_disconnect, handle, reason);
399 }
400 
SetSystemSuspendState(bool suspended)401 void AclManager::SetSystemSuspendState(bool suspended) {
402   CallOn(pimpl_->le_impl_, &le_impl::set_system_suspend_state, suspended);
403 }
404 
GetLeAddressManager()405 LeAddressManager* AclManager::GetLeAddressManager() {
406   return pimpl_->le_impl_->le_address_manager_;
407 }
408 
HACK_GetHandle(Address address)409 uint16_t AclManager::HACK_GetHandle(Address address) {
410   return pimpl_->classic_impl_->HACK_get_handle(address);
411 }
412 
HACK_GetLeHandle(Address address)413 uint16_t AclManager::HACK_GetLeHandle(Address address) {
414   return pimpl_->le_impl_->HACK_get_handle(address);
415 }
416 
HACK_GetLeAddress(uint16_t connection_handle)417 Address AclManager::HACK_GetLeAddress(uint16_t connection_handle) {
418   return pimpl_->le_impl_->HACK_get_address(connection_handle);
419 }
420 
HACK_SetAclTxPriority(uint8_t handle,bool high_priority)421 void AclManager::HACK_SetAclTxPriority(uint8_t handle, bool high_priority) {
422   CallOn(pimpl_->round_robin_scheduler_, &RoundRobinScheduler::SetLinkPriority, handle, high_priority);
423 }
424 
ListDependencies(ModuleList * list) const425 void AclManager::ListDependencies(ModuleList* list) const {
426   list->add<HciLayer>();
427   list->add<Controller>();
428   list->add<storage::StorageModule>();
429   list->add<AclScheduler>();
430   list->add<RemoteNameRequestModule>();
431 }
432 
Start()433 void AclManager::Start() {
434   pimpl_->Start();
435 }
436 
Stop()437 void AclManager::Stop() {
438   pimpl_->Stop();
439 }
440 
ToString() const441 std::string AclManager::ToString() const {
442   return "Acl Manager";
443 }
444 
__anon33ac91890502() 445 const ModuleFactory AclManager::Factory = ModuleFactory([]() { return new AclManager(); });
446 
447 AclManager::~AclManager() = default;
448 
Dump(std::promise<flatbuffers::Offset<AclManagerData>> promise,flatbuffers::FlatBufferBuilder * fb_builder) const449 void AclManager::impl::Dump(
450     std::promise<flatbuffers::Offset<AclManagerData>> promise, flatbuffers::FlatBufferBuilder* fb_builder) const {
451   const std::lock_guard<std::mutex> lock(dumpsys_mutex_);
452   const auto accept_list = (le_impl_ != nullptr) ? le_impl_->accept_list : std::unordered_set<AddressWithType>();
453   const auto le_connectability_state_text =
454       (le_impl_ != nullptr) ? connectability_state_machine_text(le_impl_->connectability_state_) : "INDETERMINATE";
455   const auto le_create_connection_timeout_alarms_count =
456       (le_impl_ != nullptr) ? (int)le_impl_->create_connection_timeout_alarms_.size() : 0;
457 
458   auto title = fb_builder->CreateString("----- Acl Manager Dumpsys -----");
459   auto le_connectability_state = fb_builder->CreateString(le_connectability_state_text);
460 
461   flatbuffers::Offset<flatbuffers::String> strings[accept_list.size()];
462 
463   size_t cnt = 0;
464   for (const auto& it : accept_list) {
465     strings[cnt++] = fb_builder->CreateString(it.ToString());
466   }
467   auto vecofstrings = fb_builder->CreateVector(strings, accept_list.size());
468 
469   AclManagerDataBuilder builder(*fb_builder);
470   builder.add_title(title);
471   builder.add_le_filter_accept_list_count(accept_list.size());
472   builder.add_le_filter_accept_list(vecofstrings);
473   builder.add_le_connectability_state(le_connectability_state);
474   builder.add_le_create_connection_timeout_alarms_count(le_create_connection_timeout_alarms_count);
475 
476   flatbuffers::Offset<AclManagerData> dumpsys_data = builder.Finish();
477   promise.set_value(dumpsys_data);
478 }
479 
GetDumpsysData(flatbuffers::FlatBufferBuilder * fb_builder) const480 DumpsysDataFinisher AclManager::GetDumpsysData(flatbuffers::FlatBufferBuilder* fb_builder) const {
481   log::assert_that(fb_builder != nullptr, "assert failed: fb_builder != nullptr");
482 
483   std::promise<flatbuffers::Offset<AclManagerData>> promise;
484   auto future = promise.get_future();
485   pimpl_->Dump(std::move(promise), fb_builder);
486 
487   auto dumpsys_data = future.get();
488 
489   return [dumpsys_data](DumpsysDataBuilder* dumpsys_builder) {
490     dumpsys_builder->add_hci_acl_manager_dumpsys_data(dumpsys_data);
491   };
492 }
493 
494 }  // namespace hci
495 }  // namespace bluetooth
496