Skip to content

Commit

Permalink
Sync with aosp/main
Browse files Browse the repository at this point in the history
Synchronized to packages/modules/Bluetooth
commit ed4ceaf45f86efe5d37e842605308e5ddc8f34ad

Changelist:
- Fix directed advertising with privacy enabled
- Fix endianness of version numbers in android vendor capabilities
  • Loading branch information
hchataing committed Feb 2, 2024
1 parent 72d015c commit 92b8672
Show file tree
Hide file tree
Showing 6 changed files with 259 additions and 20 deletions.
22 changes: 19 additions & 3 deletions model/controller/le_advertiser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,10 @@ slots operator"" _slots(unsigned long long count) { return slots(count); }
// =============================================================================

// Vol 6, Part B § 4.4.2.4.3 High duty cycle connectable directed advertising.
// NB: The interval is specified to be 3.75ms, but it does not make sense to
// use this value with the timer tick at 5ms.
const chrono::duration adv_direct_ind_high_timeout = 1280ms;
const chrono::duration adv_direct_ind_high_interval = 3750us;
const chrono::duration adv_direct_ind_high_interval = 10ms /*3750us*/;

// Vol 6, Part B § 2.3.4.9 Host Advertising Data.
const uint16_t max_legacy_advertising_pdu_size = 31;
Expand Down Expand Up @@ -546,7 +548,7 @@ ErrorCode LinkLayerController::LeSetExtendedAdvertisingParameters(
#if 0
if (advertiser.periodic_advertising_enable) {
// TODO
INFO(id_,
INFO(id_,
"periodic advertising is enabled for the specified advertising set"
" and the secondary PHY does not match the periodic"
" advertising PHY");
Expand Down Expand Up @@ -1148,6 +1150,19 @@ ErrorCode LinkLayerController::LeSetExtendedAdvertisingEnable(
}
break;
}

// If an IRK is available in the Link Layer Resolving List for the peer
// device, then the target’s device address (TargetA field) shall
// use a resolvable private address. If an IRK is not available in the
// Link Layer Resolving List or the IRK is set to zero for the peer device,
// then the target’s device address (TargetA field) shall use the Identity
// Address when entering the Advertising State and using connectable
// directed events.
if (advertiser.IsDirected()) {
advertiser.target_address =
GenerateResolvablePrivateAddress(peer_address, IrkSelection::Peer)
.value_or(peer_address);
}
}

for (auto& set : sets) {
Expand Down Expand Up @@ -1661,7 +1676,8 @@ void LinkLayerController::LeAdvertising() {
// Generate Link Layer Advertising events when advertising is enabled
// and a full interval has passed since the last event.
if (legacy_advertiser_.IsEnabled() && now >= legacy_advertiser_.next_event) {
legacy_advertiser_.next_event += legacy_advertiser_.advertising_interval;
legacy_advertiser_.next_event =
now + legacy_advertiser_.advertising_interval;
model::packets::LegacyAdvertisingType type;
bool attach_advertising_data = true;
switch (legacy_advertiser_.advertising_type) {
Expand Down
22 changes: 12 additions & 10 deletions model/controller/link_layer_controller.cc
Original file line number Diff line number Diff line change
Expand Up @@ -262,10 +262,6 @@ bool LinkLayerController::ValidateTargetA(AddressWithType target_a,
std::optional<AddressWithType>
LinkLayerController::GenerateResolvablePrivateAddress(AddressWithType address,
IrkSelection irk) {
if (!le_resolving_list_enabled_) {
return {};
}

for (auto& entry : le_resolving_list_) {
if (address.GetAddress() == entry.peer_identity_address &&
address.ToPeerAddressType() == entry.peer_identity_address_type) {
Expand Down Expand Up @@ -4335,11 +4331,14 @@ bool LinkLayerController::ProcessIncomingLegacyConnectRequest(
// When the Link Layer is [...] connectable directed advertising events the
// advertising filter policy shall be ignored.
if (legacy_advertiser_.IsDirected()) {
if (legacy_advertiser_.GetTargetAddress() != resolved_initiating_address) {
if (resolved_initiating_address !=
PeerDeviceAddress(legacy_advertiser_.peer_address,
legacy_advertiser_.peer_address_type)) {
DEBUG(id_,
"LE Connect request ignored by legacy advertiser because the "
"initiating address {} does not match the target address {}",
resolved_initiating_address, legacy_advertiser_.GetTargetAddress());
"initiating address {} does not match the target address {}[{}]",
resolved_initiating_address, legacy_advertiser_.peer_address,
PeerAddressTypeText(legacy_advertiser_.peer_address_type));
return false;
}
} else {
Expand Down Expand Up @@ -4446,12 +4445,15 @@ bool LinkLayerController::ProcessIncomingExtendedConnectRequest(
// When the Link Layer is [...] connectable directed advertising events the
// advertising filter policy shall be ignored.
if (advertiser.IsDirected()) {
if (advertiser.GetTargetAddress() != resolved_initiating_address) {
if (resolved_initiating_address !=
PeerDeviceAddress(advertiser.peer_address,
advertiser.peer_address_type)) {
DEBUG(id_,
"LE Connect request ignored by extended advertiser {} because the "
"initiating address {} does not match the target address {}",
"initiating address {} does not match the target address {}[{}]",
advertiser.advertising_handle, resolved_initiating_address,
advertiser.GetTargetAddress());
advertiser.peer_address,
PeerAddressTypeText(advertiser.peer_address_type));
return false;
}
} else {
Expand Down
6 changes: 3 additions & 3 deletions packets/hci_packets.pdl
Original file line number Diff line number Diff line change
Expand Up @@ -5646,7 +5646,7 @@ struct VendorCapabilities_V_0_96 {
filtering_support: 8,
max_filter: 8,
activity_energy_info_support: 8,
_fixed_ = 0x6000 : 16, // v0.96
_fixed_ = 0x0060 : 16, // v0.96
total_num_of_advt_tracked: 16,
extended_scan_support: 8,
debug_logging_supported: 8,
Expand All @@ -5661,7 +5661,7 @@ struct VendorCapabilities_V_0_98 {
filtering_support: 8,
max_filter: 8,
activity_energy_info_support: 8,
_fixed_ = 0x6200 : 16, // v0.98
_fixed_ = 0x0062 : 16, // v0.98
total_num_of_advt_tracked: 16,
extended_scan_support: 8,
debug_logging_supported: 8,
Expand All @@ -5678,7 +5678,7 @@ struct VendorCapabilities_V_1_03 {
filtering_support: 8,
max_filter: 8,
activity_energy_info_support: 8,
_fixed_ = 0x0301 : 16, // v1.03
_fixed_ = 0x0103 : 16, // v1.03
total_num_of_advt_tracked: 16,
extended_scan_support: 8,
debug_logging_supported: 8,
Expand Down
4 changes: 0 additions & 4 deletions test/LL/DDI/ADV/BV_11_C.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,6 @@ async def test(self):
conn_supervision_timeout=self.LL_initiator_connSupervisionTimeout),
rssi=-16)

# Note: another advertising pdu is received waiting from the connect
# complete.
await self.expect_ll(ll.LeLegacyAdvertisingPdu)

# Note: Link layer sends LeConnectComplete here.
await self.expect_ll(
ll.LeConnectComplete(source_address=controller.address,
Expand Down
224 changes: 224 additions & 0 deletions test/LL/SEC/ADV/BV_11_C.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
# Copyright 2023 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import asyncio
import hci_packets as hci
import link_layer_packets as ll
import math
import random
import unittest
from dataclasses import dataclass
from hci_packets import ErrorCode, FragmentPreference
from py.bluetooth import Address
from py.controller import ControllerTest, generate_rpa
from typing import List


@dataclass
class TestRound:
data_length: int


class Test(ControllerTest):
# Test parameters.
LL_advertiser_advInterval_MIN = 0x800
LL_advertiser_advInterval_MAX = 0x800
LL_advertiser_Adv_Channel_Map = 0x7
LL_initiator_connInterval = 0x200
LL_initiator_connPeripheralLatency = 0x200
LL_initiator_connSupervisionTimeout = 0x200

# LL/SEC/ADV/BV-11-C [Network Privacy - Directed Connectable Advertising
# using local and remote IRK]
#
# Verify that the IUT, when transmitting directed connectable advertising
# events, is using resolvable private addresses for AdvA and InitA fields
# when the Lower Tester has distributed its own IRK.
#
# Verify that when address resolution is disabled on the IUT, the Lower
# Tester resolvable private address is not resolved, and therefore a
# connection is not established.
async def test(self):
controller = self.controller
local_irk = bytes([1] * 16)
peer_irk = bytes([2] * 16)
random_irk = bytes([3] * 16)
peer_address = Address('aa:bb:cc:dd:ee:ff')

# 1. The Lower Tester adds the Device Identity of the IUT to its resolving list.
# 2. Configure the Lower Tester to initiate a connection while using a resolvable private address.

# 3. The Upper Tester populates the resolving list with the device identity of the Lower Tester
# connected with the local device identity. The IUT use these when generating resolvable private
# addresses for use in the advertising packet’s AdvA and InitA fields.
controller.send_cmd(
hci.LeAddDeviceToResolvingList(
peer_irk=peer_irk,
local_irk=local_irk,
peer_identity_address=peer_address,
peer_identity_address_type=hci.PeerAddressType.PUBLIC_DEVICE_OR_IDENTITY_ADDRESS))

await self.expect_evt(
hci.LeAddDeviceToResolvingListComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1))

controller.send_cmd(hci.LeSetResolvablePrivateAddressTimeout(rpa_timeout=0x10))

await self.expect_evt(
hci.LeSetResolvablePrivateAddressTimeoutComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1))

# 4. The Upper Tester enables resolving list and directed connectable advertising in the IUT.
controller.send_cmd(
hci.LeSetAdvertisingParameters(advertising_interval_min=Test.LL_advertiser_advInterval_MIN,
advertising_interval_max=Test.LL_advertiser_advInterval_MAX,
advertising_type=hci.AdvertisingType.ADV_DIRECT_IND_HIGH,
own_address_type=hci.OwnAddressType.RESOLVABLE_OR_PUBLIC_ADDRESS,
peer_address=peer_address,
peer_address_type=hci.PeerAddressType.PUBLIC_DEVICE_OR_IDENTITY_ADDRESS,
advertising_channel_map=0x7,
advertising_filter_policy=hci.AdvertisingFilterPolicy.ALL_DEVICES))

await self.expect_evt(
hci.LeSetAdvertisingParametersComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1))

controller.send_cmd(hci.LeSetAdvertisingData())

await self.expect_evt(hci.LeSetAdvertisingDataComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1))

controller.send_cmd(hci.LeSetAddressResolutionEnable(address_resolution_enable=hci.Enable.ENABLED))

await self.expect_evt(
hci.LeSetAddressResolutionEnableComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1))

controller.send_cmd(hci.LeSetAdvertisingEnable(advertising_enable=True))

await self.expect_evt(hci.LeSetAdvertisingEnableComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1))

# 5. The Lower Tester expects the IUT to send ADV_DIRECT_IND packets on an applicable
# advertising channel.
direct_ind = await self.expect_ll(ll.LeLegacyAdvertisingPdu(
source_address=self.Any,
destination_address=self.Any,
advertising_address_type=ll.AddressType.RANDOM,
target_address_type=ll.AddressType.RANDOM,
advertising_type=ll.LegacyAdvertisingType.ADV_DIRECT_IND,
advertising_data=[]),
timeout=5)

self.assertTrue(direct_ind.source_address.is_resolvable())
self.assertTrue(direct_ind.destination_address.is_resolvable())

# 6. The Lower Tester identifies the IUT. The Lower Tester sends a CONNECT_IND with the AdvA
# address of the ADV_DIRECT_IND and the InitA generated based on its Device Identity. The IUT
# verifies AdvA and resolves the InitA Address and identifies the Lower Tester.
# 7. The Lower Tester connects to the IUT. The Lower Tester sends empty LL DATA packets starting
# with the first event one connection interval after the connection request using the common data
# channel selection parameters.
init_a = generate_rpa(peer_irk)
controller.send_ll(
ll.LeConnect(source_address=init_a,
destination_address=direct_ind.source_address,
initiating_address_type=ll.AddressType.RANDOM,
advertising_address_type=ll.AddressType.RANDOM,
conn_interval=Test.LL_initiator_connInterval,
conn_peripheral_latency=0x6,
conn_supervision_timeout=0xc80))

await self.expect_ll(
ll.LeConnectComplete(source_address=direct_ind.source_address,
destination_address=init_a,
initiating_address_type=ll.AddressType.RANDOM,
advertising_address_type=ll.AddressType.RANDOM,
conn_interval=Test.LL_initiator_connInterval,
conn_peripheral_latency=0x6,
conn_supervision_timeout=0xc80))

connection_complete_evt = await self.expect_evt(
hci.LeEnhancedConnectionComplete(
status=hci.ErrorCode.SUCCESS,
connection_handle=self.Any,
role=hci.Role.PERIPHERAL,
peer_address_type=hci.AddressType.PUBLIC_DEVICE_ADDRESS,
peer_address=peer_address,
local_resolvable_private_address=direct_ind.source_address,
peer_resolvable_private_address=init_a,
connection_interval=0x200,
peripheral_latency=0x6,
supervision_timeout=0xc80,
central_clock_accuracy=hci.ClockAccuracy.PPM_500,
))

# 8. The Upper Tester terminates the connection.
controller.send_cmd(
hci.Disconnect(connection_handle=connection_complete_evt.connection_handle,
reason=hci.DisconnectReason.REMOTE_USER_TERMINATED_CONNECTION))

await self.expect_evt(hci.DisconnectStatus(status=ErrorCode.SUCCESS, num_hci_command_packets=1))

await self.expect_ll(
ll.Disconnect(source_address=direct_ind.source_address,
destination_address=init_a,
reason=hci.DisconnectReason.REMOTE_USER_TERMINATED_CONNECTION))

await self.expect_evt(
hci.DisconnectionComplete(status=ErrorCode.SUCCESS,
connection_handle=connection_complete_evt.connection_handle,
reason=ErrorCode.CONNECTION_TERMINATED_BY_LOCAL_HOST))

# 9. The Upper Tester disables address resolution in the IUT.
controller.send_cmd(hci.LeSetAddressResolutionEnable(address_resolution_enable=hci.Enable.DISABLED))

await self.expect_evt(
hci.LeSetAddressResolutionEnableComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1))

# 10. Repeat steps 11–14 at least 20 times.

# 11. The Upper Tester enables directed connectable advertising in the IUT.
controller.send_cmd(hci.LeSetAdvertisingEnable(advertising_enable=True))

await self.expect_evt(hci.LeSetAdvertisingEnableComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1))

# 12. The Lower Tester expects the IUT to send ADV_DIRECT_IND packets on an applicable
# advertising channel. The Lower Tester resolves the AdvA address and identifies the IUT.
direct_ind = await self.expect_ll(ll.LeLegacyAdvertisingPdu(
source_address=self.Any,
destination_address=self.Any,
advertising_address_type=ll.AddressType.RANDOM,
target_address_type=ll.AddressType.RANDOM,
advertising_type=ll.LegacyAdvertisingType.ADV_DIRECT_IND,
advertising_data=[]),
timeout=5)

self.assertTrue(direct_ind.source_address.is_resolvable())
self.assertTrue(direct_ind.destination_address.is_resolvable())

# 13. The Lower Tester sends a CONNECT_IND with the AdvA address of the ADV_IND and the InitA
# set to a different address than the last CONNECT_IND. The IUT does not resolve the address in
# the InitA field. No connection event is sent to the Upper Tester.
init_a = generate_rpa(local_irk)
controller.send_ll(
ll.LeConnect(source_address=init_a,
destination_address=direct_ind.source_address,
initiating_address_type=ll.AddressType.RANDOM,
advertising_address_type=ll.AddressType.RANDOM,
conn_interval=0x200,
conn_peripheral_latency=0x6,
conn_supervision_timeout=0xc80))

# 14. The Upper Tester receives an HCI_LE_Connection_Complete event or an
# HCI_LE_Enhanced_Connection_Complete event with the Status code set to Advertising Timeout
# (0x3C).
await self.expect_evt(hci.LeConnectionComplete(status=hci.ErrorCode.ADVERTISING_TIMEOUT,))

# Empty the LL queue.
controller.ll_queue.clear()
1 change: 1 addition & 0 deletions test/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
'LL.DDI.SCN.BV_18_C',
'LL.DDI.SCN.BV_19_C',
'LL.DDI.SCN.BV_79_C',
'LL.SEC.ADV.BV_11_C',
'LMP.LIH.BV_01_C',
'LMP.LIH.BV_02_C',
'LMP.LIH.BV_78_C',
Expand Down

0 comments on commit 92b8672

Please sign in to comment.