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 #define LOG_TAG "bt_gd_neigh"
17 
18 #include "neighbor/inquiry.h"
19 
20 #include <memory>
21 
22 #include "common/bind.h"
23 #include "hci/hci_layer.h"
24 #include "hci/hci_packets.h"
25 #include "module.h"
26 #include "os/handler.h"
27 #include "os/log.h"
28 
29 namespace bluetooth {
30 namespace neighbor {
31 
32 static constexpr uint8_t kGeneralInquiryAccessCode = 0x33;
33 static constexpr uint8_t kLimitedInquiryAccessCode = 0x00;
34 
35 struct InquiryModule::impl {
36   void RegisterCallbacks(InquiryCallbacks inquiry_callbacks);
37   void UnregisterCallbacks();
38 
39   void StartOneShotInquiry(bool limited, InquiryLength inquiry_length, NumResponses num_responses);
40   void StopOneShotInquiry();
41 
42   void StartPeriodicInquiry(
43       bool limited,
44       InquiryLength inquiry_length,
45       NumResponses num_responses,
46       PeriodLength max_delay,
47       PeriodLength min_delay);
48   void StopPeriodicInquiry();
49 
50   void SetScanActivity(ScanParameters params);
51 
52   void SetScanType(hci::InquiryScanType scan_type);
53 
54   void SetInquiryMode(hci::InquiryMode mode);
55 
56   void Start();
57   void Stop();
58 
59   bool HasCallbacks() const;
60 
61   impl(InquiryModule& inquiry_module);
62 
63  private:
64   InquiryCallbacks inquiry_callbacks_;
65 
66   InquiryModule& module_;
67 
68   bool active_general_one_shot_{false};
69   bool active_limited_one_shot_{false};
70   bool active_general_periodic_{false};
71   bool active_limited_periodic_{false};
72 
73   ScanParameters inquiry_scan_;
74   hci::InquiryMode inquiry_mode_;
75   hci::InquiryScanType inquiry_scan_type_;
76   int8_t inquiry_response_tx_power_;
77 
78   bool IsInquiryActive() const;
79 
80   void EnqueueCommandComplete(std::unique_ptr<hci::CommandBuilder> command);
81   void EnqueueCommandStatus(std::unique_ptr<hci::CommandBuilder> command);
82   void OnCommandComplete(hci::CommandCompleteView view);
83   void OnCommandStatus(hci::CommandStatusView status);
84 
85   void EnqueueCommandCompleteSync(std::unique_ptr<hci::CommandBuilder> command);
86   void OnCommandCompleteSync(hci::CommandCompleteView view);
87 
88   void OnEvent(hci::EventView view);
89 
90   std::promise<void>* command_sync_{nullptr};
91 
92   hci::HciLayer* hci_layer_;
93   os::Handler* handler_;
94 };
95 
__anon5363d6b40102() 96 const ModuleFactory neighbor::InquiryModule::Factory = ModuleFactory([]() { return new neighbor::InquiryModule(); });
97 
impl(neighbor::InquiryModule & module)98 neighbor::InquiryModule::impl::impl(neighbor::InquiryModule& module) : module_(module) {}
99 
OnCommandCompleteSync(hci::CommandCompleteView view)100 void neighbor::InquiryModule::impl::OnCommandCompleteSync(hci::CommandCompleteView view) {
101   OnCommandComplete(view);
102   ASSERT(command_sync_ != nullptr);
103   command_sync_->set_value();
104 }
105 
OnCommandComplete(hci::CommandCompleteView view)106 void neighbor::InquiryModule::impl::OnCommandComplete(hci::CommandCompleteView view) {
107   switch (view.GetCommandOpCode()) {
108     case hci::OpCode::INQUIRY_CANCEL: {
109       auto packet = hci::InquiryCancelCompleteView::Create(view);
110       ASSERT(packet.IsValid());
111       ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
112     } break;
113 
114     case hci::OpCode::PERIODIC_INQUIRY_MODE: {
115       auto packet = hci::PeriodicInquiryModeCompleteView::Create(view);
116       ASSERT(packet.IsValid());
117       ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
118     } break;
119 
120     case hci::OpCode::EXIT_PERIODIC_INQUIRY_MODE: {
121       auto packet = hci::ExitPeriodicInquiryModeCompleteView::Create(view);
122       ASSERT(packet.IsValid());
123       ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
124     } break;
125 
126     case hci::OpCode::WRITE_INQUIRY_MODE: {
127       auto packet = hci::WriteInquiryModeCompleteView::Create(view);
128       ASSERT(packet.IsValid());
129       ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
130     } break;
131 
132     case hci::OpCode::READ_INQUIRY_MODE: {
133       auto packet = hci::ReadInquiryModeCompleteView::Create(view);
134       ASSERT(packet.IsValid());
135       ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
136       inquiry_mode_ = packet.GetInquiryMode();
137     } break;
138 
139     case hci::OpCode::READ_INQUIRY_RESPONSE_TRANSMIT_POWER_LEVEL: {
140       auto packet = hci::ReadInquiryResponseTransmitPowerLevelCompleteView::Create(view);
141       ASSERT(packet.IsValid());
142       ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
143       inquiry_response_tx_power_ = packet.GetTxPower();
144     } break;
145 
146     case hci::OpCode::WRITE_INQUIRY_SCAN_ACTIVITY: {
147       auto packet = hci::WriteInquiryScanActivityCompleteView::Create(view);
148       ASSERT(packet.IsValid());
149       ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
150     } break;
151 
152     case hci::OpCode::READ_INQUIRY_SCAN_ACTIVITY: {
153       auto packet = hci::ReadInquiryScanActivityCompleteView::Create(view);
154       ASSERT(packet.IsValid());
155       ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
156       inquiry_scan_.interval = packet.GetInquiryScanInterval();
157       inquiry_scan_.window = packet.GetInquiryScanWindow();
158     } break;
159 
160     case hci::OpCode::WRITE_INQUIRY_SCAN_TYPE: {
161       auto packet = hci::WriteInquiryScanTypeCompleteView::Create(view);
162       ASSERT(packet.IsValid());
163       ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
164     } break;
165 
166     case hci::OpCode::READ_INQUIRY_SCAN_TYPE: {
167       auto packet = hci::ReadInquiryScanTypeCompleteView::Create(view);
168       ASSERT(packet.IsValid());
169       ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
170       inquiry_scan_type_ = packet.GetInquiryScanType();
171     } break;
172 
173     default:
174       LOG_WARN("Unhandled command:%s", hci::OpCodeText(view.GetCommandOpCode()).c_str());
175       break;
176   }
177 }
178 
OnCommandStatus(hci::CommandStatusView status)179 void neighbor::InquiryModule::impl::OnCommandStatus(hci::CommandStatusView status) {
180   ASSERT(status.GetStatus() == hci::ErrorCode::SUCCESS);
181 
182   switch (status.GetCommandOpCode()) {
183     case hci::OpCode::INQUIRY: {
184       auto packet = hci::InquiryStatusView::Create(status);
185       ASSERT(packet.IsValid());
186       if (active_limited_one_shot_ || active_general_one_shot_) {
187         LOG_INFO("Inquiry started lap: %s", active_limited_one_shot_ ? "Limited" : "General");
188       }
189     } break;
190 
191     default:
192       LOG_WARN("Unhandled command:%s", hci::OpCodeText(status.GetCommandOpCode()).c_str());
193       break;
194   }
195 }
196 
OnEvent(hci::EventView view)197 void neighbor::InquiryModule::impl::OnEvent(hci::EventView view) {
198   switch (view.GetEventCode()) {
199     case hci::EventCode::INQUIRY_COMPLETE: {
200       auto packet = hci::InquiryCompleteView::Create(view);
201       ASSERT(packet.IsValid());
202       LOG_INFO("inquiry complete");
203       active_limited_one_shot_ = false;
204       active_general_one_shot_ = false;
205       inquiry_callbacks_.complete(packet.GetStatus());
206     } break;
207 
208     case hci::EventCode::INQUIRY_RESULT: {
209       auto packet = hci::InquiryResultView::Create(view);
210       ASSERT(packet.IsValid());
211       LOG_INFO("Inquiry result size:%zd num_responses:%zu", packet.size(), packet.GetInquiryResults().size());
212       inquiry_callbacks_.result(packet);
213     } break;
214 
215     case hci::EventCode::INQUIRY_RESULT_WITH_RSSI: {
216       auto packet = hci::InquiryResultWithRssiView::Create(view);
217       ASSERT(packet.IsValid());
218       LOG_INFO("Inquiry result with rssi num_responses:%zu", packet.GetInquiryResults().size());
219       inquiry_callbacks_.result_with_rssi(packet);
220     } break;
221 
222     case hci::EventCode::EXTENDED_INQUIRY_RESULT: {
223       auto packet = hci::ExtendedInquiryResultView::Create(view);
224       ASSERT(packet.IsValid());
225       LOG_INFO(
226           "Extended inquiry result addr:%s repetition_mode:%s cod:%s clock_offset:%d rssi:%hhd",
227           packet.GetAddress().ToString().c_str(),
228           hci::PageScanRepetitionModeText(packet.GetPageScanRepetitionMode()).c_str(),
229           packet.GetClassOfDevice().ToString().c_str(),
230           packet.GetClockOffset(),
231           packet.GetRssi());
232       inquiry_callbacks_.extended_result(packet);
233     } break;
234 
235     default:
236       LOG_ERROR("Unhandled event:%s", hci::EventCodeText(view.GetEventCode()).c_str());
237       break;
238   }
239 }
240 
241 /**
242  * impl
243  */
RegisterCallbacks(InquiryCallbacks callbacks)244 void neighbor::InquiryModule::impl::RegisterCallbacks(InquiryCallbacks callbacks) {
245   inquiry_callbacks_ = callbacks;
246 
247   hci_layer_->RegisterEventHandler(
248       hci::EventCode::INQUIRY_RESULT, handler_->BindOn(this, &InquiryModule::impl::OnEvent));
249   hci_layer_->RegisterEventHandler(
250       hci::EventCode::INQUIRY_RESULT_WITH_RSSI, handler_->BindOn(this, &InquiryModule::impl::OnEvent));
251   hci_layer_->RegisterEventHandler(
252       hci::EventCode::EXTENDED_INQUIRY_RESULT, handler_->BindOn(this, &InquiryModule::impl::OnEvent));
253   hci_layer_->RegisterEventHandler(
254       hci::EventCode::INQUIRY_COMPLETE, handler_->BindOn(this, &InquiryModule::impl::OnEvent));
255 }
256 
UnregisterCallbacks()257 void neighbor::InquiryModule::impl::UnregisterCallbacks() {
258   hci_layer_->UnregisterEventHandler(hci::EventCode::INQUIRY_COMPLETE);
259   hci_layer_->UnregisterEventHandler(hci::EventCode::EXTENDED_INQUIRY_RESULT);
260   hci_layer_->UnregisterEventHandler(hci::EventCode::INQUIRY_RESULT_WITH_RSSI);
261   hci_layer_->UnregisterEventHandler(hci::EventCode::INQUIRY_RESULT);
262 
263   inquiry_callbacks_ = {nullptr, nullptr, nullptr, nullptr};
264 }
265 
EnqueueCommandComplete(std::unique_ptr<hci::CommandBuilder> command)266 void neighbor::InquiryModule::impl::EnqueueCommandComplete(std::unique_ptr<hci::CommandBuilder> command) {
267   hci_layer_->EnqueueCommand(std::move(command), handler_->BindOnceOn(this, &impl::OnCommandComplete));
268 }
269 
EnqueueCommandStatus(std::unique_ptr<hci::CommandBuilder> command)270 void neighbor::InquiryModule::impl::EnqueueCommandStatus(std::unique_ptr<hci::CommandBuilder> command) {
271   hci_layer_->EnqueueCommand(std::move(command), handler_->BindOnceOn(this, &impl::OnCommandStatus));
272 }
273 
EnqueueCommandCompleteSync(std::unique_ptr<hci::CommandBuilder> command)274 void neighbor::InquiryModule::impl::EnqueueCommandCompleteSync(std::unique_ptr<hci::CommandBuilder> command) {
275   ASSERT(command_sync_ == nullptr);
276   command_sync_ = new std::promise<void>();
277   auto command_received = command_sync_->get_future();
278   hci_layer_->EnqueueCommand(std::move(command), handler_->BindOnceOn(this, &impl::OnCommandCompleteSync));
279   command_received.wait();
280   delete command_sync_;
281   command_sync_ = nullptr;
282 }
283 
StartOneShotInquiry(bool limited,InquiryLength inquiry_length,NumResponses num_responses)284 void neighbor::InquiryModule::impl::StartOneShotInquiry(
285     bool limited, InquiryLength inquiry_length, NumResponses num_responses) {
286   ASSERT(HasCallbacks());
287   ASSERT(!IsInquiryActive());
288   hci::Lap lap;
289   if (limited) {
290     active_limited_one_shot_ = true;
291     lap.lap_ = kLimitedInquiryAccessCode;
292   } else {
293     active_general_one_shot_ = true;
294     lap.lap_ = kGeneralInquiryAccessCode;
295   }
296   EnqueueCommandStatus(hci::InquiryBuilder::Create(lap, inquiry_length, num_responses));
297 }
298 
StopOneShotInquiry()299 void neighbor::InquiryModule::impl::StopOneShotInquiry() {
300   ASSERT(active_general_one_shot_ || active_limited_one_shot_);
301   active_general_one_shot_ = false;
302   active_limited_one_shot_ = false;
303   EnqueueCommandComplete(hci::InquiryCancelBuilder::Create());
304 }
305 
StartPeriodicInquiry(bool limited,InquiryLength inquiry_length,NumResponses num_responses,PeriodLength max_delay,PeriodLength min_delay)306 void neighbor::InquiryModule::impl::StartPeriodicInquiry(
307     bool limited,
308     InquiryLength inquiry_length,
309     NumResponses num_responses,
310     PeriodLength max_delay,
311     PeriodLength min_delay) {
312   ASSERT(HasCallbacks());
313   ASSERT(!IsInquiryActive());
314   hci::Lap lap;
315   if (limited) {
316     active_limited_periodic_ = true;
317     lap.lap_ = kLimitedInquiryAccessCode;
318   } else {
319     active_general_periodic_ = true;
320     lap.lap_ = kGeneralInquiryAccessCode;
321   }
322   EnqueueCommandComplete(
323       hci::PeriodicInquiryModeBuilder::Create(max_delay, min_delay, lap, inquiry_length, num_responses));
324 }
325 
StopPeriodicInquiry()326 void neighbor::InquiryModule::impl::StopPeriodicInquiry() {
327   ASSERT(active_general_periodic_ || active_limited_periodic_);
328   active_general_periodic_ = false;
329   active_limited_periodic_ = false;
330   EnqueueCommandComplete(hci::ExitPeriodicInquiryModeBuilder::Create());
331 }
332 
IsInquiryActive() const333 bool neighbor::InquiryModule::impl::IsInquiryActive() const {
334   return active_general_one_shot_ || active_limited_one_shot_ || active_limited_periodic_ || active_general_periodic_;
335 }
336 
Start()337 void neighbor::InquiryModule::impl::Start() {
338   hci_layer_ = module_.GetDependency<hci::HciLayer>();
339   handler_ = module_.GetHandler();
340 
341   EnqueueCommandComplete(hci::ReadInquiryResponseTransmitPowerLevelBuilder::Create());
342   EnqueueCommandComplete(hci::ReadInquiryScanActivityBuilder::Create());
343   EnqueueCommandComplete(hci::ReadInquiryScanTypeBuilder::Create());
344   EnqueueCommandCompleteSync(hci::ReadInquiryModeBuilder::Create());
345 
346   LOG_INFO("Started inquiry module");
347 }
348 
Stop()349 void neighbor::InquiryModule::impl::Stop() {
350   LOG_INFO("Inquiry scan interval:%hu window:%hu", inquiry_scan_.interval, inquiry_scan_.window);
351   LOG_INFO(
352       "Inquiry mode:%s scan_type:%s",
353       hci::InquiryModeText(inquiry_mode_).c_str(),
354       hci::InquiryScanTypeText(inquiry_scan_type_).c_str());
355   LOG_INFO("Inquiry response tx power:%hhd", inquiry_response_tx_power_);
356   LOG_INFO("Stopped inquiry module");
357 }
358 
SetInquiryMode(hci::InquiryMode mode)359 void neighbor::InquiryModule::impl::SetInquiryMode(hci::InquiryMode mode) {
360   EnqueueCommandComplete(hci::WriteInquiryModeBuilder::Create(mode));
361   inquiry_mode_ = mode;
362   LOG_INFO("Set inquiry mode:%s", hci::InquiryModeText(mode).c_str());
363 }
364 
SetScanActivity(ScanParameters params)365 void neighbor::InquiryModule::impl::SetScanActivity(ScanParameters params) {
366   EnqueueCommandComplete(hci::WriteInquiryScanActivityBuilder::Create(params.interval, params.window));
367   inquiry_scan_ = params;
368   LOG_INFO(
369       "Set scan activity interval:0x%x/%.02fms window:0x%x/%.02fms",
370       params.interval,
371       ScanIntervalTimeMs(params.interval),
372       params.window,
373       ScanWindowTimeMs(params.window));
374 }
375 
SetScanType(hci::InquiryScanType scan_type)376 void neighbor::InquiryModule::impl::SetScanType(hci::InquiryScanType scan_type) {
377   EnqueueCommandComplete(hci::WriteInquiryScanTypeBuilder::Create(scan_type));
378   LOG_INFO("Set scan type:%s", hci::InquiryScanTypeText(scan_type).c_str());
379 }
380 
HasCallbacks() const381 bool neighbor::InquiryModule::impl::HasCallbacks() const {
382   return inquiry_callbacks_.result != nullptr && inquiry_callbacks_.result_with_rssi != nullptr &&
383          inquiry_callbacks_.extended_result != nullptr && inquiry_callbacks_.complete != nullptr;
384 }
385 
386 /**
387  * General API here
388  */
InquiryModule()389 neighbor::InquiryModule::InquiryModule() : pimpl_(std::make_unique<impl>(*this)) {}
390 
~InquiryModule()391 neighbor::InquiryModule::~InquiryModule() {
392   pimpl_.reset();
393 }
394 
RegisterCallbacks(InquiryCallbacks callbacks)395 void neighbor::InquiryModule::RegisterCallbacks(InquiryCallbacks callbacks) {
396   pimpl_->RegisterCallbacks(callbacks);
397 }
398 
UnregisterCallbacks()399 void neighbor::InquiryModule::UnregisterCallbacks() {
400   pimpl_->UnregisterCallbacks();
401 }
402 
StartGeneralInquiry(InquiryLength inquiry_length,NumResponses num_responses)403 void neighbor::InquiryModule::StartGeneralInquiry(InquiryLength inquiry_length, NumResponses num_responses) {
404   GetHandler()->Post(common::BindOnce(
405       &neighbor::InquiryModule::impl::StartOneShotInquiry,
406       common::Unretained(pimpl_.get()),
407       false,
408       inquiry_length,
409       num_responses));
410 }
411 
StartLimitedInquiry(InquiryLength inquiry_length,NumResponses num_responses)412 void neighbor::InquiryModule::StartLimitedInquiry(InquiryLength inquiry_length, NumResponses num_responses) {
413   GetHandler()->Post(common::BindOnce(
414       &neighbor::InquiryModule::impl::StartOneShotInquiry,
415       common::Unretained(pimpl_.get()),
416       true,
417       inquiry_length,
418       num_responses));
419 }
420 
StopInquiry()421 void neighbor::InquiryModule::StopInquiry() {
422   GetHandler()->Post(
423       common::BindOnce(&neighbor::InquiryModule::impl::StopOneShotInquiry, common::Unretained(pimpl_.get())));
424 }
425 
StartGeneralPeriodicInquiry(InquiryLength inquiry_length,NumResponses num_responses,PeriodLength max_delay,PeriodLength min_delay)426 void neighbor::InquiryModule::StartGeneralPeriodicInquiry(
427     InquiryLength inquiry_length, NumResponses num_responses, PeriodLength max_delay, PeriodLength min_delay) {
428   GetHandler()->Post(common::BindOnce(
429       &neighbor::InquiryModule::impl::StartPeriodicInquiry,
430       common::Unretained(pimpl_.get()),
431       false,
432       inquiry_length,
433       num_responses,
434       max_delay,
435       min_delay));
436 }
437 
StartLimitedPeriodicInquiry(InquiryLength inquiry_length,NumResponses num_responses,PeriodLength max_delay,PeriodLength min_delay)438 void neighbor::InquiryModule::StartLimitedPeriodicInquiry(
439     InquiryLength inquiry_length, NumResponses num_responses, PeriodLength max_delay, PeriodLength min_delay) {
440   GetHandler()->Post(common::BindOnce(
441       &neighbor::InquiryModule::impl::StartPeriodicInquiry,
442       common::Unretained(pimpl_.get()),
443       true,
444       inquiry_length,
445       num_responses,
446       max_delay,
447       min_delay));
448 }
449 
StopPeriodicInquiry()450 void neighbor::InquiryModule::StopPeriodicInquiry() {
451   GetHandler()->Post(
452       common::BindOnce(&neighbor::InquiryModule::impl::StopPeriodicInquiry, common::Unretained(pimpl_.get())));
453 }
454 
SetScanActivity(ScanParameters params)455 void neighbor::InquiryModule::SetScanActivity(ScanParameters params) {
456   GetHandler()->Post(
457       common::BindOnce(&neighbor::InquiryModule::impl::SetScanActivity, common::Unretained(pimpl_.get()), params));
458 }
459 
SetInterlacedScan()460 void neighbor::InquiryModule::SetInterlacedScan() {
461   GetHandler()->Post(common::BindOnce(
462       &neighbor::InquiryModule::impl::SetScanType, common::Unretained(pimpl_.get()), hci::InquiryScanType::INTERLACED));
463 }
464 
SetStandardScan()465 void neighbor::InquiryModule::SetStandardScan() {
466   GetHandler()->Post(common::BindOnce(
467       &neighbor::InquiryModule::impl::SetScanType, common::Unretained(pimpl_.get()), hci::InquiryScanType::STANDARD));
468 }
469 
SetStandardInquiryResultMode()470 void neighbor::InquiryModule::SetStandardInquiryResultMode() {
471   GetHandler()->Post(common::BindOnce(
472       &neighbor::InquiryModule::impl::SetInquiryMode, common::Unretained(pimpl_.get()), hci::InquiryMode::STANDARD));
473 }
474 
SetInquiryWithRssiResultMode()475 void neighbor::InquiryModule::SetInquiryWithRssiResultMode() {
476   GetHandler()->Post(common::BindOnce(
477       &neighbor::InquiryModule::impl::SetInquiryMode, common::Unretained(pimpl_.get()), hci::InquiryMode::RSSI));
478 }
479 
SetExtendedInquiryResultMode()480 void neighbor::InquiryModule::SetExtendedInquiryResultMode() {
481   GetHandler()->Post(common::BindOnce(
482       &neighbor::InquiryModule::impl::SetInquiryMode,
483       common::Unretained(pimpl_.get()),
484       hci::InquiryMode::RSSI_OR_EXTENDED));
485 }
486 
487 /**
488  * Module methods here
489  */
ListDependencies(ModuleList * list)490 void neighbor::InquiryModule::ListDependencies(ModuleList* list) {
491   list->add<hci::HciLayer>();
492 }
493 
Start()494 void neighbor::InquiryModule::Start() {
495   pimpl_->Start();
496 }
497 
Stop()498 void neighbor::InquiryModule::Stop() {
499   pimpl_->Stop();
500 }
501 
502 }  // namespace neighbor
503 }  // namespace bluetooth
504