Floss: Fix handle_set_terminated
Some controllers will send the the HCI event
HCI_LE_Advertising_Set_Terminated with the status
HCI_ERROR_CANCELLED_BY_HOST when the host stops the advertisement.
This event is NOT generated when the host stops the advertisement.
Refer to the BT spec ver 5.3 vol 4 part E sec 7.7.65.18. Note that the
section was revised from BT spec ver 5.0 vol 2 part E sec 7.7.65.18
which was ambiguous about.
Bug: 261410147
Test: Manually
Tag: #floss
Change-Id: I6c3bd5fe084faac23edca75bc0be799272f27a1c
diff --git a/system/gd/hci/hci_packets.pdl b/system/gd/hci/hci_packets.pdl
index 718e29e..b776cc6 100644
--- a/system/gd/hci/hci_packets.pdl
+++ b/system/gd/hci/hci_packets.pdl
@@ -938,6 +938,7 @@
CONNECTION_FAILED_ESTABLISHMENT = 0x3E,
UNKNOWN_ADVERTISING_IDENTIFIER = 0x42,
LIMIT_REACHED = 0x43,
+ OPERATION_CANCELLED_BY_HOST = 0x44,
PACKET_TOO_LONG = 0x45,
}
diff --git a/system/gd/hci/le_advertising_manager.cc b/system/gd/hci/le_advertising_manager.cc
index 43dab69..33f1b94 100644
--- a/system/gd/hci/le_advertising_manager.cc
+++ b/system/gd/hci/le_advertising_manager.cc
@@ -221,7 +221,20 @@
LOG_INFO("Dropping invalid advertising event");
return;
}
- LOG_VERBOSE("Received LE Advertising Set Terminated with status %s", ErrorCodeText(event_view.GetStatus()).c_str());
+
+ auto status = event_view.GetStatus();
+ LOG_VERBOSE(
+ "Received LE Advertising Set Terminated with status %s", ErrorCodeText(status).c_str());
+
+ /* The Bluetooth Core 5.3 specification clearly states that this event
+ * shall not be sent when the Host disables the advertising set. So in
+ * case of HCI_ERROR_CANCELLED_BY_HOST, just ignore the event.
+ */
+ if (status == ErrorCode::OPERATION_CANCELLED_BY_HOST) {
+ LOG_WARN(
+ "Unexpected advertising set terminated event status: %s", ErrorCodeText(status).c_str());
+ return;
+ }
uint8_t advertiser_id = event_view.GetAdvertisingHandle();
@@ -236,13 +249,13 @@
AddressWithType advertiser_address = advertising_sets_[event_view.GetAdvertisingHandle()].current_address;
bool is_discoverable = advertising_sets_[event_view.GetAdvertisingHandle()].discoverable;
- auto status = event_view.GetStatus();
acl_manager_->OnAdvertisingSetTerminated(
status,
event_view.GetConnectionHandle(),
advertiser_id,
advertiser_address,
is_discoverable);
+
if (status == ErrorCode::LIMIT_REACHED || status == ErrorCode::ADVERTISING_TIMEOUT) {
if (id_map_[advertiser_id] == kIdLocal) {
if (!advertising_sets_[advertiser_id].timeout_callback.is_null()) {