• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2023 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/internal/host/hci/extended_low_energy_advertiser.h"
16 
17 #include <pw_assert/check.h>
18 
19 #include "pw_bluetooth_sapphire/internal/host/transport/transport.h"
20 
21 namespace bt::hci {
22 namespace pwemb = pw::bluetooth::emboss;
23 
ExtendedLowEnergyAdvertiser(hci::Transport::WeakPtr hci_ptr,uint16_t max_advertising_data_length)24 ExtendedLowEnergyAdvertiser::ExtendedLowEnergyAdvertiser(
25     hci::Transport::WeakPtr hci_ptr, uint16_t max_advertising_data_length)
26     : LowEnergyAdvertiser(std::move(hci_ptr), max_advertising_data_length) {
27   event_handler_id_ = hci()->command_channel()->AddLEMetaEventHandler(
28       hci_spec::kLEAdvertisingSetTerminatedSubeventCode,
29       [this](const EventPacket& event) {
30         OnAdvertisingSetTerminatedEvent(event);
31         return CommandChannel::EventCallbackResult::kContinue;
32       });
33 }
34 
~ExtendedLowEnergyAdvertiser()35 ExtendedLowEnergyAdvertiser::~ExtendedLowEnergyAdvertiser() {
36   // This object is probably being destroyed because the stack is shutting down,
37   // in which case the HCI layer may have already been destroyed.
38   if (!hci().is_alive() || !hci()->command_channel()) {
39     return;
40   }
41 
42   hci()->command_channel()->RemoveEventHandler(event_handler_id_);
43 
44   // TODO(fxbug.dev/42063496): This will only cancel one advertisement,
45   // after which the SequentialCommandRunner will have been destroyed and no
46   // further commands will be sent.
47   StopAdvertising();
48 }
49 
BuildEnablePacket(const DeviceAddress & address,pwemb::GenericEnableParam enable,bool extended_pdu)50 CommandPacket ExtendedLowEnergyAdvertiser::BuildEnablePacket(
51     const DeviceAddress& address,
52     pwemb::GenericEnableParam enable,
53     bool extended_pdu) {
54   // We only enable or disable a single address at a time. The multiply by 1 is
55   // set explicitly to show that data[] within
56   // LESetExtendedAdvertisingEnableData is of size 1.
57   constexpr size_t kPacketSize =
58       pwemb::LESetExtendedAdvertisingEnableCommand::MinSizeInBytes() +
59       (1 * pwemb::LESetExtendedAdvertisingEnableData::IntrinsicSizeInBytes());
60   auto packet = hci::CommandPacket::New<
61       pwemb::LESetExtendedAdvertisingEnableCommandWriter>(
62       hci_spec::kLESetExtendedAdvertisingEnable, kPacketSize);
63   auto view = packet.view_t();
64   view.enable().Write(enable);
65   view.num_sets().Write(1);
66 
67   std::optional<hci_spec::AdvertisingHandle> handle =
68       advertising_handle_map_.GetHandle(address, extended_pdu);
69   PW_CHECK(handle);
70 
71   view.data()[0].advertising_handle().Write(handle.value());
72   view.data()[0].duration().Write(hci_spec::kNoAdvertisingDuration);
73   view.data()[0].max_extended_advertising_events().Write(
74       hci_spec::kNoMaxExtendedAdvertisingEvents);
75 
76   return packet;
77 }
78 
WriteAdvertisingEventProperties(const ExtendedLowEnergyAdvertiser::AdvertisingEventProperties & properties,pwemb::LESetExtendedAdvertisingParametersV1CommandWriter & view)79 static void WriteAdvertisingEventProperties(
80     const ExtendedLowEnergyAdvertiser::AdvertisingEventProperties& properties,
81     pwemb::LESetExtendedAdvertisingParametersV1CommandWriter& view) {
82   view.advertising_event_properties().connectable().Write(
83       properties.connectable);
84   view.advertising_event_properties().scannable().Write(properties.scannable);
85   view.advertising_event_properties().directed().Write(properties.directed);
86   view.advertising_event_properties()
87       .high_duty_cycle_directed_connectable()
88       .Write(properties.high_duty_cycle_directed_connectable);
89   view.advertising_event_properties().use_legacy_pdus().Write(
90       properties.use_legacy_pdus);
91   view.advertising_event_properties().anonymous_advertising().Write(
92       properties.anonymous_advertising);
93   view.advertising_event_properties().include_tx_power().Write(
94       properties.include_tx_power);
95 }
96 
97 std::optional<CommandPacket>
BuildSetAdvertisingParams(const DeviceAddress & address,const AdvertisingEventProperties & properties,pwemb::LEOwnAddressType own_address_type,const AdvertisingIntervalRange & interval,bool extended_pdu)98 ExtendedLowEnergyAdvertiser::BuildSetAdvertisingParams(
99     const DeviceAddress& address,
100     const AdvertisingEventProperties& properties,
101     pwemb::LEOwnAddressType own_address_type,
102     const AdvertisingIntervalRange& interval,
103     bool extended_pdu) {
104   auto packet = hci::CommandPacket::New<
105       pwemb::LESetExtendedAdvertisingParametersV1CommandWriter>(
106       hci_spec::kLESetExtendedAdvertisingParameters);
107   auto view = packet.view_t();
108 
109   // advertising handle
110   std::optional<hci_spec::AdvertisingHandle> handle =
111       advertising_handle_map_.MapHandle(address, extended_pdu);
112   if (!handle) {
113     bt_log(WARN,
114            "hci-le",
115            "could not allocate advertising handle for address: %s",
116            bt_str(address));
117     return std::nullopt;
118   }
119   view.advertising_handle().Write(handle.value());
120 
121   WriteAdvertisingEventProperties(properties, view);
122 
123   // advertising interval, NOTE: LE advertising parameters allow for up to 3
124   // octets (10 ms to 10428 s) to configure an advertising interval. However, we
125   // expose only the recommended advertising interval configurations to users,
126   // as specified in the Bluetooth Spec Volume 3, Part C, Appendix A. These
127   // values are expressed as uint16_t so we simply copy them (taking care of
128   // endianness) into the 3 octets as is.
129   view.primary_advertising_interval_min().Write(interval.min());
130   view.primary_advertising_interval_max().Write(interval.max());
131 
132   // advertise on all channels
133   view.primary_advertising_channel_map().channel_37().Write(true);
134   view.primary_advertising_channel_map().channel_38().Write(true);
135   view.primary_advertising_channel_map().channel_39().Write(true);
136 
137   view.own_address_type().Write(own_address_type);
138   view.advertising_filter_policy().Write(
139       pwemb::LEAdvertisingFilterPolicy::ALLOW_ALL);
140   view.advertising_tx_power().Write(
141       hci_spec::kLEExtendedAdvertisingTxPowerNoPreference);
142   view.scan_request_notification_enable().Write(
143       pwemb::GenericEnableParam::DISABLE);
144 
145   // TODO(fxbug.dev/42161929): using legacy PDUs requires advertisements
146   // on the LE 1M PHY.
147   view.primary_advertising_phy().Write(pwemb::LEPrimaryAdvertisingPHY::LE_1M);
148   view.secondary_advertising_phy().Write(
149       pwemb::LESecondaryAdvertisingPHY::LE_1M);
150 
151   // Payload values were initialized to zero above. By not setting the values
152   // for the following fields, we are purposely ignoring them:
153   //
154   // advertising_sid: We use only legacy PDUs, the controller ignores this field
155   // in that case peer_address: We don't support directed advertising yet
156   // peer_address_type: We don't support directed advertising yet
157   // secondary_adv_max_skip: We use only legacy PDUs, the controller ignores
158   // this field in that case
159 
160   return packet;
161 }
162 
163 // TODO(fxbug.dev/330935479): we can reduce code duplication by
164 // templatizing this method. However, we first have to rename
165 // advertising_data_length and advertising_data in
166 // LESetExtendedAdvertisingDataCommand to just data_length and data,
167 // respectively. We would also have to do the same in
168 // LESetExtendedScanResponseDataCommand. It's not worth it to do this rename
169 // right now since Sapphire lives in the Fuchsia repository and we would need to
170 // do an Emboss naming transition. Once Sapphire is back in the Pigweed
171 // repository, we can do this in one fell swoop rather than going through the
172 // Emboss naming transition.
BuildAdvertisingDataFragmentPacket(hci_spec::AdvertisingHandle handle,const BufferView & data,pwemb::LESetExtendedAdvDataOp operation,pwemb::LEExtendedAdvFragmentPreference fragment_preference)173 CommandPacket ExtendedLowEnergyAdvertiser::BuildAdvertisingDataFragmentPacket(
174     hci_spec::AdvertisingHandle handle,
175     const BufferView& data,
176     pwemb::LESetExtendedAdvDataOp operation,
177     pwemb::LEExtendedAdvFragmentPreference fragment_preference) {
178   size_t kPayloadSize =
179       pwemb::LESetExtendedAdvertisingDataCommandView::MinSizeInBytes().Read() +
180       data.size();
181   auto packet =
182       CommandPacket::New<pwemb::LESetExtendedAdvertisingDataCommandWriter>(
183           hci_spec::kLESetExtendedAdvertisingData, kPayloadSize);
184   auto params = packet.view_t();
185 
186   params.advertising_handle().Write(handle);
187   params.operation().Write(operation);
188   params.fragment_preference().Write(fragment_preference);
189   params.advertising_data_length().Write(static_cast<uint8_t>(data.size()));
190 
191   MutableBufferView data_view(params.advertising_data().BackingStorage().data(),
192                               data.size());
193   data.Copy(&data_view);
194 
195   return packet;
196 }
197 
BuildScanResponseDataFragmentPacket(hci_spec::AdvertisingHandle handle,const BufferView & data,pwemb::LESetExtendedAdvDataOp operation,pwemb::LEExtendedAdvFragmentPreference fragment_preference)198 CommandPacket ExtendedLowEnergyAdvertiser::BuildScanResponseDataFragmentPacket(
199     hci_spec::AdvertisingHandle handle,
200     const BufferView& data,
201     pwemb::LESetExtendedAdvDataOp operation,
202     pwemb::LEExtendedAdvFragmentPreference fragment_preference) {
203   size_t kPayloadSize =
204       pwemb::LESetExtendedScanResponseDataCommandView::MinSizeInBytes().Read() +
205       data.size();
206   auto packet =
207       CommandPacket::New<pwemb::LESetExtendedScanResponseDataCommandWriter>(
208           hci_spec::kLESetExtendedScanResponseData, kPayloadSize);
209   auto params = packet.view_t();
210 
211   params.advertising_handle().Write(handle);
212   params.operation().Write(operation);
213   params.fragment_preference().Write(fragment_preference);
214   params.scan_response_data_length().Write(static_cast<uint8_t>(data.size()));
215 
216   MutableBufferView data_view(
217       params.scan_response_data().BackingStorage().data(), data.size());
218   data.Copy(&data_view);
219 
220   return packet;
221 }
222 
BuildSetAdvertisingData(const DeviceAddress & address,const AdvertisingData & data,AdvFlags flags,bool extended_pdu)223 std::vector<CommandPacket> ExtendedLowEnergyAdvertiser::BuildSetAdvertisingData(
224     const DeviceAddress& address,
225     const AdvertisingData& data,
226     AdvFlags flags,
227     bool extended_pdu) {
228   if (data.CalculateBlockSize() == 0) {
229     std::vector<CommandPacket> packets;
230     return packets;
231   }
232 
233   AdvertisingData adv_data;
234   data.Copy(&adv_data);
235   if (staged_advertising_parameters_.include_tx_power_level) {
236     adv_data.SetTxPower(staged_advertising_parameters_.selected_tx_power_level);
237   }
238 
239   std::optional<hci_spec::AdvertisingHandle> handle =
240       advertising_handle_map_.GetHandle(address, extended_pdu);
241   PW_CHECK(handle);
242 
243   size_t block_size = adv_data.CalculateBlockSize(/*include_flags=*/true);
244   DynamicByteBuffer buffer(block_size);
245   adv_data.WriteBlock(&buffer, flags);
246 
247   size_t max_length =
248       pwemb::LESetExtendedAdvertisingDataCommand::advertising_data_length_max();
249 
250   // If all data fits into a single HCI packet, we don't need to do any
251   // fragmentation ourselves. The Controller may still perform fragmentation
252   // over the air but we don't have to when sending the data to the Controller.
253   if (block_size <= max_length) {
254     CommandPacket packet = BuildAdvertisingDataFragmentPacket(
255         handle.value(),
256         buffer.view(),
257         pwemb::LESetExtendedAdvDataOp::COMPLETE,
258         pwemb::LEExtendedAdvFragmentPreference::SHOULD_NOT_FRAGMENT);
259 
260     std::vector<CommandPacket> packets;
261     packets.reserve(1);
262     packets.emplace_back(std::move(packet));
263     return packets;
264   }
265 
266   // We have more data than will fit in a single HCI packet. Calculate the
267   // amount of packets we need to send, perform the fragmentation, and queue up
268   // the multiple LE Set Extended Advertising Data packets to the Controller.
269   size_t num_packets = block_size / max_length;
270   if (block_size % max_length != 0) {
271     num_packets++;
272   }
273 
274   std::vector<CommandPacket> packets;
275   packets.reserve(num_packets);
276 
277   for (size_t i = 0; i < num_packets; i++) {
278     size_t packet_size = max_length;
279     pwemb::LESetExtendedAdvDataOp operation =
280         pwemb::LESetExtendedAdvDataOp::INTERMEDIATE_FRAGMENT;
281 
282     if (i == 0) {
283       operation = pwemb::LESetExtendedAdvDataOp::FIRST_FRAGMENT;
284     } else if (i == num_packets - 1) {
285       operation = pwemb::LESetExtendedAdvDataOp::LAST_FRAGMENT;
286 
287       if (block_size % max_length != 0) {
288         packet_size = block_size % max_length;
289       }
290     }
291 
292     size_t offset = i * max_length;
293     BufferView buffer_view(buffer.data() + offset, packet_size);
294 
295     CommandPacket packet = BuildAdvertisingDataFragmentPacket(
296         handle.value(),
297         buffer_view,
298         operation,
299         pwemb::LEExtendedAdvFragmentPreference::SHOULD_NOT_FRAGMENT);
300     packets.push_back(packet);
301   }
302 
303   return packets;
304 }
305 
BuildUnsetAdvertisingData(const DeviceAddress & address,bool extended_pdu)306 CommandPacket ExtendedLowEnergyAdvertiser::BuildUnsetAdvertisingData(
307     const DeviceAddress& address, bool extended_pdu) {
308   constexpr size_t kPacketSize =
309       pwemb::LESetExtendedAdvertisingDataCommandView::MinSizeInBytes().Read();
310   auto packet =
311       CommandPacket::New<pwemb::LESetExtendedAdvertisingDataCommandWriter>(
312           hci_spec::kLESetExtendedAdvertisingData, kPacketSize);
313   auto payload = packet.view_t();
314 
315   // advertising handle
316   std::optional<hci_spec::AdvertisingHandle> handle =
317       advertising_handle_map_.GetHandle(address, extended_pdu);
318   PW_CHECK(handle);
319   payload.advertising_handle().Write(handle.value());
320 
321   payload.operation().Write(pwemb::LESetExtendedAdvDataOp::COMPLETE);
322   payload.fragment_preference().Write(
323       pwemb::LEExtendedAdvFragmentPreference::SHOULD_NOT_FRAGMENT);
324   payload.advertising_data_length().Write(0);
325 
326   return packet;
327 }
328 
BuildSetScanResponse(const DeviceAddress & address,const AdvertisingData & data,bool extended_pdu)329 std::vector<CommandPacket> ExtendedLowEnergyAdvertiser::BuildSetScanResponse(
330     const DeviceAddress& address,
331     const AdvertisingData& data,
332     bool extended_pdu) {
333   if (data.CalculateBlockSize() == 0) {
334     std::vector<CommandPacket> packets;
335     return packets;
336   }
337 
338   AdvertisingData scan_rsp;
339   data.Copy(&scan_rsp);
340   if (staged_advertising_parameters_.include_tx_power_level) {
341     scan_rsp.SetTxPower(staged_advertising_parameters_.selected_tx_power_level);
342   }
343 
344   std::optional<hci_spec::AdvertisingHandle> handle =
345       advertising_handle_map_.GetHandle(address, extended_pdu);
346   PW_CHECK(handle);
347 
348   size_t block_size = scan_rsp.CalculateBlockSize(/*include_flags=*/false);
349   DynamicByteBuffer buffer(block_size);
350   scan_rsp.WriteBlock(&buffer, std::nullopt);
351 
352   size_t max_length = pwemb::LESetExtendedScanResponseDataCommand::
353       scan_response_data_length_max();
354 
355   // If all data fits into a single HCI packet, we don't need to do any
356   // fragmentation ourselves. The Controller may still perform fragmentation
357   // over the air but we don't have to when sending the data to the Controller.
358   if (block_size <= max_length) {
359     CommandPacket packet = BuildScanResponseDataFragmentPacket(
360         handle.value(),
361         buffer.view(),
362         pwemb::LESetExtendedAdvDataOp::COMPLETE,
363         pwemb::LEExtendedAdvFragmentPreference::SHOULD_NOT_FRAGMENT);
364 
365     std::vector<CommandPacket> packets;
366     packets.reserve(1);
367     packets.emplace_back(std::move(packet));
368     return packets;
369   }
370 
371   // We have more data than will fit in a single HCI packet. Calculate the
372   // amount of packets we need to send, perform the fragmentation, and queue up
373   // the multiple LE Set Extended Advertising Data packets to the Controller.
374   size_t num_packets = block_size / max_length;
375   if (block_size % max_length != 0) {
376     num_packets++;
377   }
378 
379   std::vector<CommandPacket> packets;
380   packets.reserve(num_packets);
381 
382   for (size_t i = 0; i < num_packets; i++) {
383     size_t packet_size = max_length;
384     pwemb::LESetExtendedAdvDataOp operation =
385         pwemb::LESetExtendedAdvDataOp::INTERMEDIATE_FRAGMENT;
386 
387     if (i == 0) {
388       operation = pwemb::LESetExtendedAdvDataOp::FIRST_FRAGMENT;
389     } else if (i == num_packets - 1) {
390       operation = pwemb::LESetExtendedAdvDataOp::LAST_FRAGMENT;
391 
392       if (block_size % max_length != 0) {
393         packet_size = block_size % max_length;
394       }
395     }
396 
397     size_t offset = i * max_length;
398     BufferView buffer_view(buffer.data() + offset, packet_size);
399 
400     CommandPacket packet = BuildScanResponseDataFragmentPacket(
401         handle.value(),
402         buffer_view,
403         operation,
404         pwemb::LEExtendedAdvFragmentPreference::SHOULD_NOT_FRAGMENT);
405     packets.push_back(packet);
406   }
407 
408   return packets;
409 }
410 
BuildUnsetScanResponse(const DeviceAddress & address,bool extended_pdu)411 CommandPacket ExtendedLowEnergyAdvertiser::BuildUnsetScanResponse(
412     const DeviceAddress& address, bool extended_pdu) {
413   constexpr size_t kPacketSize =
414       pwemb::LESetExtendedScanResponseDataCommandView::MinSizeInBytes().Read();
415   auto packet =
416       CommandPacket::New<pwemb::LESetExtendedScanResponseDataCommandWriter>(
417           hci_spec::kLESetExtendedScanResponseData, kPacketSize);
418   auto payload = packet.view_t();
419 
420   // advertising handle
421   std::optional<hci_spec::AdvertisingHandle> handle =
422       advertising_handle_map_.GetHandle(address, extended_pdu);
423   PW_CHECK(handle);
424   payload.advertising_handle().Write(handle.value());
425 
426   payload.operation().Write(pwemb::LESetExtendedAdvDataOp::COMPLETE);
427   payload.fragment_preference().Write(
428       pwemb::LEExtendedAdvFragmentPreference::SHOULD_NOT_FRAGMENT);
429   payload.scan_response_data_length().Write(0);
430 
431   return packet;
432 }
433 
BuildRemoveAdvertisingSet(const DeviceAddress & address,bool extended_pdu)434 CommandPacket ExtendedLowEnergyAdvertiser::BuildRemoveAdvertisingSet(
435     const DeviceAddress& address, bool extended_pdu) {
436   std::optional<hci_spec::AdvertisingHandle> handle =
437       advertising_handle_map_.GetHandle(address, extended_pdu);
438   PW_CHECK(handle);
439   auto packet =
440       hci::CommandPacket::New<pwemb::LERemoveAdvertisingSetCommandWriter>(
441           hci_spec::kLERemoveAdvertisingSet);
442   auto view = packet.view_t();
443   view.advertising_handle().Write(handle.value());
444 
445   return packet;
446 }
447 
OnSetAdvertisingParamsComplete(const EventPacket & event)448 void ExtendedLowEnergyAdvertiser::OnSetAdvertisingParamsComplete(
449     const EventPacket& event) {
450   auto event_view = event.view<pw::bluetooth::emboss::EventHeaderView>();
451   PW_CHECK(event_view.event_code().Read() ==
452            pw::bluetooth::emboss::EventCode::COMMAND_COMPLETE);
453 
454   auto cmd_complete_view =
455       event.view<pw::bluetooth::emboss::CommandCompleteEventView>();
456   PW_CHECK(
457       cmd_complete_view.command_opcode().Read() ==
458       pw::bluetooth::emboss::OpCode::LE_SET_EXTENDED_ADVERTISING_PARAMETERS_V1);
459 
460   Result<> result = event.ToResult();
461   if (bt_is_error(result,
462                   WARN,
463                   "hci-le",
464                   "set advertising parameters, error received: %s",
465                   bt_str(result))) {
466     return;  // full error handling done in super class, can just return here
467   }
468 
469   auto view = event.view<
470       pw::bluetooth::emboss::
471           LESetExtendedAdvertisingParametersCommandCompleteEventView>();
472   if (staged_advertising_parameters_.include_tx_power_level) {
473     staged_advertising_parameters_.selected_tx_power_level =
474         view.selected_tx_power().Read();
475   }
476 }
477 
StartAdvertising(const DeviceAddress & address,const AdvertisingData & data,const AdvertisingData & scan_rsp,const AdvertisingOptions & options,ConnectionCallback connect_callback,ResultFunction<> result_callback)478 void ExtendedLowEnergyAdvertiser::StartAdvertising(
479     const DeviceAddress& address,
480     const AdvertisingData& data,
481     const AdvertisingData& scan_rsp,
482     const AdvertisingOptions& options,
483     ConnectionCallback connect_callback,
484     ResultFunction<> result_callback) {
485   // if there is an operation currently in progress, enqueue this operation and
486   // we will get to it the next time we have a chance
487   if (!hci_cmd_runner().IsReady()) {
488     bt_log(INFO,
489            "hci-le",
490            "hci cmd runner not ready, queuing advertisement commands for now");
491 
492     AdvertisingData copied_data;
493     data.Copy(&copied_data);
494 
495     AdvertisingData copied_scan_rsp;
496     scan_rsp.Copy(&copied_scan_rsp);
497 
498     op_queue_.push([this,
499                     address_copy = address,
500                     data_copy = std::move(copied_data),
501                     scan_rsp_copy = std::move(copied_scan_rsp),
502                     options_copy = options,
503                     conn_cb = std::move(connect_callback),
504                     result_cb = std::move(result_callback)]() mutable {
505       StartAdvertising(address_copy,
506                        data_copy,
507                        scan_rsp_copy,
508                        options_copy,
509                        std::move(conn_cb),
510                        std::move(result_cb));
511     });
512 
513     return;
514   }
515 
516   fit::result<HostError> result =
517       CanStartAdvertising(address, data, scan_rsp, options, connect_callback);
518   if (result.is_error()) {
519     result_callback(ToResult(result.error_value()));
520     return;
521   }
522 
523   if (IsAdvertising(address, options.extended_pdu)) {
524     bt_log(DEBUG,
525            "hci-le",
526            "updating existing advertisement for %s",
527            bt_str(address));
528   }
529 
530   staged_advertising_parameters_.clear();
531   staged_advertising_parameters_.include_tx_power_level =
532       options.include_tx_power_level;
533   staged_advertising_parameters_.extended_pdu = options.extended_pdu;
534 
535   // Core Spec, Volume 4, Part E, Section 7.8.58: "the number of advertising
536   // sets that can be supported is not fixed and the Controller can change it at
537   // any time. The memory used to store advertising sets can also be used for
538   // other purposes."
539   //
540   // Depending on the memory profile of the controller, a new advertising set
541   // may or may not be accepted. We could use
542   // HCI_LE_Read_Number_of_Supported_Advertising_Sets to check if the controller
543   // has space for another advertising set. However, the value may change after
544   // the read and before the addition of the advertising set. Furthermore,
545   // sending an extra HCI command increases the latency of our stack. Instead,
546   // we simply attempt to add. If the controller is unable to support another
547   // advertising set, it will respond with a memory capacity exceeded error.
548   StartAdvertisingInternal(address,
549                            data,
550                            scan_rsp,
551                            options,
552                            std::move(connect_callback),
553                            std::move(result_callback));
554 }
555 
StopAdvertising()556 void ExtendedLowEnergyAdvertiser::StopAdvertising() {
557   LowEnergyAdvertiser::StopAdvertising();
558   advertising_handle_map_.Clear();
559 
560   // std::queue doesn't have a clear method so we have to resort to this
561   // tomfoolery :(
562   decltype(op_queue_) empty;
563   std::swap(op_queue_, empty);
564 }
565 
StopAdvertising(const DeviceAddress & address,bool extended_pdu)566 void ExtendedLowEnergyAdvertiser::StopAdvertising(const DeviceAddress& address,
567                                                   bool extended_pdu) {
568   // if there is an operation currently in progress, enqueue this operation and
569   // we will get to it the next time we have a chance
570   if (!hci_cmd_runner().IsReady()) {
571     bt_log(
572         INFO,
573         "hci-le",
574         "hci cmd runner not ready, queueing stop advertising command for now");
575     op_queue_.push([this, address, extended_pdu]() {
576       StopAdvertising(address, extended_pdu);
577     });
578     return;
579   }
580 
581   LowEnergyAdvertiser::StopAdvertisingInternal(address, extended_pdu);
582   advertising_handle_map_.RemoveAddress(address, extended_pdu);
583 }
584 
OnIncomingConnection(hci_spec::ConnectionHandle handle,pwemb::ConnectionRole role,const DeviceAddress & peer_address,const hci_spec::LEConnectionParameters & conn_params)585 void ExtendedLowEnergyAdvertiser::OnIncomingConnection(
586     hci_spec::ConnectionHandle handle,
587     pwemb::ConnectionRole role,
588     const DeviceAddress& peer_address,
589     const hci_spec::LEConnectionParameters& conn_params) {
590   // Core Spec Volume 4, Part E, Section 7.8.56: Incoming connections to LE
591   // Extended Advertising occur through two events: HCI_LE_Connection_Complete
592   // and HCI_LE_Advertising_Set_Terminated. This method is called as a result of
593   // the HCI_LE_Connection_Complete event. At this point, we only have a
594   // connection handle but don't know the locally advertised address that the
595   // connection is for. Until we receive the HCI_LE_Advertising_Set_Terminated
596   // event, we stage these parameters.
597   staged_connections_[handle] = {role, peer_address, conn_params};
598 }
599 
600 // The HCI_LE_Advertising_Set_Terminated event contains the mapping between
601 // connection handle and advertising handle. After the
602 // HCI_LE_Advertising_Set_Terminated event, we have all the information
603 // necessary to create a connection object within the Host layer.
OnAdvertisingSetTerminatedEvent(const EventPacket & event)604 void ExtendedLowEnergyAdvertiser::OnAdvertisingSetTerminatedEvent(
605     const EventPacket& event) {
606   Result<> result = event.ToResult();
607   if (bt_is_error(result,
608                   ERROR,
609                   "hci-le",
610                   "advertising set terminated event, error received %s",
611                   bt_str(result))) {
612     return;
613   }
614 
615   auto params = event.view<pwemb::LEAdvertisingSetTerminatedSubeventView>();
616 
617   hci_spec::ConnectionHandle connection_handle =
618       params.connection_handle().Read();
619   auto staged_parameters_node = staged_connections_.extract(connection_handle);
620 
621   if (staged_parameters_node.empty()) {
622     bt_log(ERROR,
623            "hci-le",
624            "advertising set terminated event, staged params not available "
625            "(handle: %d)",
626            params.advertising_handle().Read());
627     return;
628   }
629 
630   hci_spec::AdvertisingHandle adv_handle = params.advertising_handle().Read();
631   std::optional<DeviceAddress> opt_local_address =
632       advertising_handle_map_.GetAddress(adv_handle);
633 
634   // We use the identity address as the local address if we aren't advertising
635   // or otherwise don't know about this advertising set. This is obviously
636   // wrong. However, the link will be disconnected in that case before it can
637   // propagate to higher layers.
638   static DeviceAddress identity_address =
639       DeviceAddress(DeviceAddress::Type::kLEPublic, {0});
640   DeviceAddress local_address = identity_address;
641   if (opt_local_address) {
642     local_address = opt_local_address.value();
643   }
644 
645   StagedConnectionParameters staged = staged_parameters_node.mapped();
646 
647   CompleteIncomingConnection(connection_handle,
648                              staged.role,
649                              local_address,
650                              staged.peer_address,
651                              staged.conn_params,
652                              staged_advertising_parameters_.extended_pdu);
653 
654   staged_advertising_parameters_.clear();
655 }
656 
OnCurrentOperationComplete()657 void ExtendedLowEnergyAdvertiser::OnCurrentOperationComplete() {
658   if (op_queue_.empty()) {
659     return;  // no more queued operations so nothing to do
660   }
661 
662   fit::closure closure = std::move(op_queue_.front());
663   op_queue_.pop();
664   closure();
665 }
666 
667 }  // namespace bt::hci
668