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 #include <memory>
17 #include <mutex>
18 
19 #include "hci/controller.h"
20 #include "hci/hci_layer.h"
21 #include "hci/hci_packets.h"
22 #include "hci/le_advertising_interface.h"
23 #include "hci/le_advertising_manager.h"
24 #include "module.h"
25 #include "os/handler.h"
26 #include "os/log.h"
27 
28 namespace bluetooth {
29 namespace hci {
30 
31 const ModuleFactory LeAdvertisingManager::Factory = ModuleFactory([]() { return new LeAdvertisingManager(); });
32 
33 enum class AdvertisingApiType {
34   LE_4_0 = 1,
35   ANDROID_HCI = 2,
36   LE_5_0 = 3,
37 };
38 
39 struct Advertiser {
40   os::Handler* handler;
41   common::Callback<void(Address, AddressType)> scan_callback;
42   common::Callback<void(ErrorCode, uint8_t, uint8_t)> set_terminated_callback;
43 };
44 
45 ExtendedAdvertisingConfig::ExtendedAdvertisingConfig(const AdvertisingConfig& config) : AdvertisingConfig(config) {
46   switch (config.event_type) {
47     case AdvertisingEventType::ADV_IND:
48       connectable = true;
49       scannable = true;
50       break;
51     case AdvertisingEventType::ADV_DIRECT_IND:
52       connectable = true;
53       directed = true;
54       high_duty_directed_connectable = true;
55       break;
56     case AdvertisingEventType::ADV_SCAN_IND:
57       scannable = true;
58       break;
59     case AdvertisingEventType::ADV_NONCONN_IND:
60       break;
61     case AdvertisingEventType::ADV_DIRECT_IND_LOW:
62       connectable = true;
63       directed = true;
64       break;
65     default:
66       LOG_WARN("Unknown event type");
67       break;
68   }
69   if (config.address_type == AddressType::PUBLIC_DEVICE_ADDRESS) {
70     own_address_type = OwnAddressType::PUBLIC_DEVICE_ADDRESS;
71   } else if (config.address_type == AddressType::RANDOM_DEVICE_ADDRESS) {
72     own_address_type = OwnAddressType::RANDOM_DEVICE_ADDRESS;
73   }
74   // TODO(b/149221472): Support fragmentation
75   operation = Operation::COMPLETE_ADVERTISEMENT;
76 }
77 
78 struct LeAdvertisingManager::impl {
79   impl(Module* module) : module_(module), le_advertising_interface_(nullptr), num_instances_(0) {}
80 
81   void start(os::Handler* handler, hci::HciLayer* hci_layer, hci::Controller* controller) {
82     module_handler_ = handler;
83     hci_layer_ = hci_layer;
84     controller_ = controller;
85     le_advertising_interface_ = hci_layer_->GetLeAdvertisingInterface(
86         common::Bind(&LeAdvertisingManager::impl::handle_event, common::Unretained(this)), module_handler_);
87     num_instances_ = controller_->GetControllerLeNumberOfSupportedAdverisingSets();
88     enabled_sets_ = std::vector<EnabledSet>(num_instances_);
89     if (controller_->IsSupported(hci::OpCode::LE_SET_EXTENDED_ADVERTISING_PARAMETERS)) {
90       advertising_api_type_ = AdvertisingApiType::LE_5_0;
91     } else if (controller_->IsSupported(hci::OpCode::LE_MULTI_ADVT)) {
92       advertising_api_type_ = AdvertisingApiType::ANDROID_HCI;
93     } else {
94       advertising_api_type_ = AdvertisingApiType::LE_4_0;
95     }
96   }
97 
98   size_t GetNumberOfAdvertisingInstances() const {
99     return num_instances_;
100   }
101 
102   void handle_event(LeMetaEventView event) {
103     switch (event.GetSubeventCode()) {
104       case hci::SubeventCode::SCAN_REQUEST_RECEIVED:
105         handle_scan_request(LeScanRequestReceivedView::Create(event));
106         break;
107       case hci::SubeventCode::ADVERTISING_SET_TERMINATED:
108         handle_set_terminated(LeAdvertisingSetTerminatedView::Create(event));
109         break;
110       default:
111         LOG_INFO("Unknown subevent in scanner %s", hci::SubeventCodeText(event.GetSubeventCode()).c_str());
112     }
113   }
114 
115   void handle_scan_request(LeScanRequestReceivedView event_view) {
116     if (!event_view.IsValid()) {
117       LOG_INFO("Dropping invalid scan request event");
118       return;
119     }
120     registered_handler_->Post(
121         common::BindOnce(scan_callback_, event_view.GetScannerAddress(), event_view.GetScannerAddressType()));
122   }
123 
124   void handle_set_terminated(LeAdvertisingSetTerminatedView event_view) {
125     if (!event_view.IsValid()) {
126       LOG_INFO("Dropping invalid advertising event");
127       return;
128     }
129     registered_handler_->Post(common::BindOnce(set_terminated_callback_, event_view.GetStatus(),
130                                                event_view.GetAdvertisingHandle(),
131                                                event_view.GetNumCompletedExtendedAdvertisingEvents()));
132   }
133 
134   AdvertiserId allocate_advertiser() {
135     AdvertiserId id = 0;
136     {
137       std::unique_lock lock(id_mutex_);
138       while (id < num_instances_ && advertising_sets_.count(id) != 0) {
139         id++;
140       }
141     }
142     if (id == num_instances_) {
143       return kInvalidId;
144     }
145     return id;
146   }
147 
148   void remove_advertiser(AdvertiserId id) {
149     stop_advertising(id);
150     std::unique_lock lock(id_mutex_);
151     if (advertising_sets_.count(id) == 0) {
152       return;
153     }
154     advertising_sets_.erase(id);
155   }
156 
157   void create_advertiser(AdvertiserId id, const AdvertisingConfig& config,
158                          const common::Callback<void(Address, AddressType)>& scan_callback,
159                          const common::Callback<void(ErrorCode, uint8_t, uint8_t)>& set_terminated_callback,
160                          os::Handler* handler) {
161     advertising_sets_[id].scan_callback = scan_callback;
162     advertising_sets_[id].set_terminated_callback = set_terminated_callback;
163     advertising_sets_[id].handler = handler;
164     switch (advertising_api_type_) {
165       case (AdvertisingApiType::LE_4_0):
166         le_advertising_interface_->EnqueueCommand(
167             hci::LeSetAdvertisingParametersBuilder::Create(
168                 config.interval_min, config.interval_max, config.event_type, config.address_type,
169                 config.peer_address_type, config.peer_address, config.channel_map, config.filter_policy),
170             common::BindOnce(impl::check_status<LeSetAdvertisingParametersCompleteView>), module_handler_);
171         le_advertising_interface_->EnqueueCommand(hci::LeSetRandomAddressBuilder::Create(config.random_address),
172                                                   common::BindOnce(impl::check_status<LeSetRandomAddressCompleteView>),
173                                                   module_handler_);
174         if (!config.scan_response.empty()) {
175           le_advertising_interface_->EnqueueCommand(
176               hci::LeSetScanResponseDataBuilder::Create(config.scan_response),
177               common::BindOnce(impl::check_status<LeSetScanResponseDataCompleteView>), module_handler_);
178         }
179         le_advertising_interface_->EnqueueCommand(
180             hci::LeSetAdvertisingDataBuilder::Create(config.advertisement),
181             common::BindOnce(impl::check_status<LeSetAdvertisingDataCompleteView>), module_handler_);
182         le_advertising_interface_->EnqueueCommand(
183             hci::LeSetAdvertisingEnableBuilder::Create(Enable::ENABLED),
184             common::BindOnce(impl::check_status<LeSetAdvertisingEnableCompleteView>), module_handler_);
185         break;
186       case (AdvertisingApiType::ANDROID_HCI):
187         le_advertising_interface_->EnqueueCommand(
188             hci::LeMultiAdvtParamBuilder::Create(config.interval_min, config.interval_max, config.event_type,
189                                                  config.address_type, config.peer_address_type, config.peer_address,
190                                                  config.channel_map, config.filter_policy, id, config.tx_power),
191             common::BindOnce(impl::check_status<LeMultiAdvtCompleteView>), module_handler_);
192         le_advertising_interface_->EnqueueCommand(hci::LeMultiAdvtSetDataBuilder::Create(config.advertisement, id),
193                                                   common::BindOnce(impl::check_status<LeMultiAdvtCompleteView>),
194                                                   module_handler_);
195         if (!config.scan_response.empty()) {
196           le_advertising_interface_->EnqueueCommand(
197               hci::LeMultiAdvtSetScanRespBuilder::Create(config.scan_response, id),
198               common::BindOnce(impl::check_status<LeMultiAdvtCompleteView>), module_handler_);
199         }
200         le_advertising_interface_->EnqueueCommand(
201             hci::LeMultiAdvtSetRandomAddrBuilder::Create(config.random_address, id),
202             common::BindOnce(impl::check_status<LeMultiAdvtCompleteView>), module_handler_);
203         le_advertising_interface_->EnqueueCommand(hci::LeMultiAdvtSetEnableBuilder::Create(Enable::ENABLED, id),
204                                                   common::BindOnce(impl::check_status<LeMultiAdvtCompleteView>),
205                                                   module_handler_);
206         break;
207       case (AdvertisingApiType::LE_5_0): {
208         ExtendedAdvertisingConfig new_config = config;
209         new_config.legacy_pdus = true;
210         create_extended_advertiser(id, new_config, scan_callback, set_terminated_callback, handler);
211       } break;
212     }
213   }
214 
215   void create_extended_advertiser(AdvertiserId id, const ExtendedAdvertisingConfig& config,
216                                   const common::Callback<void(Address, AddressType)>& scan_callback,
217                                   const common::Callback<void(ErrorCode, uint8_t, uint8_t)>& set_terminated_callback,
218                                   os::Handler* handler) {
219     if (advertising_api_type_ != AdvertisingApiType::LE_5_0) {
220       create_advertiser(id, config, scan_callback, set_terminated_callback, handler);
221       return;
222     }
223 
224     if (config.legacy_pdus) {
225       LegacyAdvertisingProperties legacy_properties = LegacyAdvertisingProperties::ADV_IND;
226       if (config.connectable && config.directed) {
227         if (config.high_duty_directed_connectable) {
228           legacy_properties = LegacyAdvertisingProperties::ADV_DIRECT_IND_HIGH;
229         } else {
230           legacy_properties = LegacyAdvertisingProperties::ADV_DIRECT_IND_LOW;
231         }
232       }
233       if (config.scannable && !config.connectable) {
234         legacy_properties = LegacyAdvertisingProperties::ADV_SCAN_IND;
235       }
236       if (!config.scannable && !config.connectable) {
237         legacy_properties = LegacyAdvertisingProperties::ADV_NONCONN_IND;
238       }
239 
240       le_advertising_interface_->EnqueueCommand(
241           LeSetExtendedAdvertisingLegacyParametersBuilder::Create(
242               id, legacy_properties, config.interval_min, config.interval_max, config.channel_map,
243               config.own_address_type, config.peer_address_type, config.peer_address, config.filter_policy,
244               config.tx_power, config.sid, config.enable_scan_request_notifications),
245           common::BindOnce(impl::check_status<LeSetExtendedAdvertisingParametersCompleteView>), module_handler_);
246     } else {
247       uint8_t legacy_properties = (config.connectable ? 0x1 : 0x00) | (config.scannable ? 0x2 : 0x00) |
248                                   (config.directed ? 0x4 : 0x00) | (config.high_duty_directed_connectable ? 0x8 : 0x00);
249       uint8_t extended_properties = (config.anonymous ? 0x20 : 0x00) | (config.include_tx_power ? 0x40 : 0x00);
250 
251       le_advertising_interface_->EnqueueCommand(
252           hci::LeSetExtendedAdvertisingParametersBuilder::Create(
253               id, legacy_properties, extended_properties, config.interval_min, config.interval_max, config.channel_map,
254               config.own_address_type, config.peer_address_type, config.peer_address, config.filter_policy,
255               config.tx_power, (config.use_le_coded_phy ? PrimaryPhyType::LE_CODED : PrimaryPhyType::LE_1M),
256               config.secondary_max_skip, config.secondary_advertising_phy, config.sid,
257               config.enable_scan_request_notifications),
258           common::BindOnce(impl::check_status<LeSetExtendedAdvertisingParametersCompleteView>), module_handler_);
259     }
260 
261     le_advertising_interface_->EnqueueCommand(
262         hci::LeSetExtendedAdvertisingRandomAddressBuilder::Create(id, config.random_address),
263         common::BindOnce(impl::check_status<LeSetExtendedAdvertisingRandomAddressCompleteView>), module_handler_);
264     if (!config.scan_response.empty()) {
265       le_advertising_interface_->EnqueueCommand(
266           hci::LeSetExtendedAdvertisingScanResponseBuilder::Create(id, config.operation, config.fragment_preference,
267                                                                    config.scan_response),
268           common::BindOnce(impl::check_status<LeSetExtendedAdvertisingScanResponseCompleteView>), module_handler_);
269     }
270     le_advertising_interface_->EnqueueCommand(
271         hci::LeSetExtendedAdvertisingDataBuilder::Create(id, config.operation, config.fragment_preference,
272                                                          config.advertisement),
273         common::BindOnce(impl::check_status<LeSetExtendedAdvertisingDataCompleteView>), module_handler_);
274 
275     EnabledSet curr_set;
276     curr_set.advertising_handle_ = id;
277     curr_set.duration_ = 0;                         // TODO: 0 means until the host disables it
278     curr_set.max_extended_advertising_events_ = 0;  // TODO: 0 is no maximum
279     std::vector<EnabledSet> enabled_sets = {curr_set};
280 
281     enabled_sets_[id] = curr_set;
282     le_advertising_interface_->EnqueueCommand(
283         hci::LeSetExtendedAdvertisingEnableBuilder::Create(Enable::ENABLED, enabled_sets),
284         common::BindOnce(impl::check_status<LeSetExtendedAdvertisingEnableCompleteView>), module_handler_);
285 
286     advertising_sets_[id].scan_callback = scan_callback;
287     advertising_sets_[id].set_terminated_callback = set_terminated_callback;
288     advertising_sets_[id].handler = handler;
289   }
290 
291   void stop_advertising(AdvertiserId advertising_set) {
292     if (advertising_sets_.find(advertising_set) == advertising_sets_.end()) {
293       LOG_INFO("Unknown advertising set %u", advertising_set);
294       return;
295     }
296     switch (advertising_api_type_) {
297       case (AdvertisingApiType::LE_4_0):
298         le_advertising_interface_->EnqueueCommand(
299             hci::LeSetAdvertisingEnableBuilder::Create(Enable::DISABLED),
300             common::BindOnce(impl::check_status<LeSetAdvertisingEnableCompleteView>), module_handler_);
301         break;
302       case (AdvertisingApiType::ANDROID_HCI):
303         le_advertising_interface_->EnqueueCommand(
304             hci::LeMultiAdvtSetEnableBuilder::Create(Enable::DISABLED, advertising_set),
305             common::BindOnce(impl::check_status<LeMultiAdvtCompleteView>), module_handler_);
306         break;
307       case (AdvertisingApiType::LE_5_0): {
308         EnabledSet curr_set;
309         curr_set.advertising_handle_ = advertising_set;
310         std::vector<EnabledSet> enabled_vector{curr_set};
311         le_advertising_interface_->EnqueueCommand(
312             hci::LeSetExtendedAdvertisingEnableBuilder::Create(Enable::DISABLED, enabled_vector),
313             common::BindOnce(impl::check_status<LeSetExtendedAdvertisingEnableCompleteView>), module_handler_);
314       } break;
315     }
316 
317     std::unique_lock lock(id_mutex_);
318     enabled_sets_[advertising_set].advertising_handle_ = -1;
319     advertising_sets_.erase(advertising_set);
320   }
321 
322   common::Callback<void(Address, AddressType)> scan_callback_;
323   common::Callback<void(ErrorCode, uint8_t, uint8_t)> set_terminated_callback_;
324   os::Handler* registered_handler_{nullptr};
325   Module* module_;
326   os::Handler* module_handler_;
327   hci::HciLayer* hci_layer_;
328   hci::Controller* controller_;
329   hci::LeAdvertisingInterface* le_advertising_interface_;
330   std::map<AdvertiserId, Advertiser> advertising_sets_;
331 
332   std::mutex id_mutex_;
333   size_t num_instances_;
334   std::vector<hci::EnabledSet> enabled_sets_;
335 
336   AdvertisingApiType advertising_api_type_{0};
337 
338   template <class View>
339   static void check_status(CommandCompleteView view) {
340     ASSERT(view.IsValid());
341     auto status_view = View::Create(view);
342     ASSERT(status_view.IsValid());
343     if (status_view.GetStatus() != ErrorCode::SUCCESS) {
344       LOG_INFO("SetEnable returned status %s", ErrorCodeText(status_view.GetStatus()).c_str());
345     }
346   }
347 };
348 
349 LeAdvertisingManager::LeAdvertisingManager() {
350   pimpl_ = std::make_unique<impl>(this);
351 }
352 
353 void LeAdvertisingManager::ListDependencies(ModuleList* list) {
354   list->add<hci::HciLayer>();
355   list->add<hci::Controller>();
356 }
357 
358 void LeAdvertisingManager::Start() {
359   pimpl_->start(GetHandler(), GetDependency<hci::HciLayer>(), GetDependency<hci::Controller>());
360 }
361 
362 void LeAdvertisingManager::Stop() {
363   pimpl_.reset();
364 }
365 
366 std::string LeAdvertisingManager::ToString() const {
367   return "Le Advertising Manager";
368 }
369 
370 size_t LeAdvertisingManager::GetNumberOfAdvertisingInstances() const {
371   return pimpl_->GetNumberOfAdvertisingInstances();
372 }
373 
374 AdvertiserId LeAdvertisingManager::CreateAdvertiser(
375     const AdvertisingConfig& config, const common::Callback<void(Address, AddressType)>& scan_callback,
376     const common::Callback<void(ErrorCode, uint8_t, uint8_t)>& set_terminated_callback, os::Handler* handler) {
377   if (config.peer_address == Address::kEmpty) {
378     if (config.address_type == hci::AddressType::PUBLIC_IDENTITY_ADDRESS ||
379         config.address_type == hci::AddressType::RANDOM_IDENTITY_ADDRESS) {
380       LOG_WARN("Peer address can not be empty");
381       return kInvalidId;
382     }
383     if (config.event_type == hci::AdvertisingEventType::ADV_DIRECT_IND ||
384         config.event_type == hci::AdvertisingEventType::ADV_DIRECT_IND_LOW) {
385       LOG_WARN("Peer address can not be empty for directed advertising");
386       return kInvalidId;
387     }
388   }
389   AdvertiserId id = pimpl_->allocate_advertiser();
390   if (id == kInvalidId) {
391     return id;
392   }
393   GetHandler()->Post(common::BindOnce(&impl::create_advertiser, common::Unretained(pimpl_.get()), id, config,
394                                       scan_callback, set_terminated_callback, handler));
395   return id;
396 }
397 
398 AdvertiserId LeAdvertisingManager::ExtendedCreateAdvertiser(
399     const ExtendedAdvertisingConfig& config, const common::Callback<void(Address, AddressType)>& scan_callback,
400     const common::Callback<void(ErrorCode, uint8_t, uint8_t)>& set_terminated_callback, os::Handler* handler) {
401   if (config.directed) {
402     if (config.peer_address == Address::kEmpty) {
403       LOG_INFO("Peer address can not be empty for directed advertising");
404       return kInvalidId;
405     }
406   }
407   if (config.channel_map == 0) {
408     LOG_INFO("At least one channel must be set in the map");
409     return kInvalidId;
410   }
411   if (!config.legacy_pdus) {
412     if (config.connectable && config.scannable) {
413       LOG_INFO("Extended advertising PDUs can not be connectable and scannable");
414       return kInvalidId;
415     }
416     if (config.high_duty_directed_connectable) {
417       LOG_INFO("Extended advertising PDUs can not be high duty cycle");
418       return kInvalidId;
419     }
420   }
421   if (config.interval_min > config.interval_max) {
422     LOG_INFO("Advertising interval: min (%hu) > max (%hu)", config.interval_min, config.interval_max);
423     return kInvalidId;
424   }
425   AdvertiserId id = pimpl_->allocate_advertiser();
426   if (id == kInvalidId) {
427     return id;
428   }
429   GetHandler()->Post(common::BindOnce(&impl::create_extended_advertiser, common::Unretained(pimpl_.get()), id, config,
430                                       scan_callback, set_terminated_callback, handler));
431   return id;
432 }
433 
434 void LeAdvertisingManager::RemoveAdvertiser(AdvertiserId id) {
435   GetHandler()->Post(common::BindOnce(&impl::remove_advertiser, common::Unretained(pimpl_.get()), id));
436 }
437 
438 }  // namespace hci
439 }  // namespace bluetooth
440