1# Copyright 2023 Google LLC
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of 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,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15import hci_packets as hci
16import link_layer_packets as ll
17import unittest
18from hci_packets import ErrorCode
19from py.bluetooth import Address
20from py.controller import ControllerTest, generate_rpa
21
22
23class Test(ControllerTest):
24
25    # Verify that the scanner gracefully handles being disabled before
26    # receiving the response to a scan request.
27    async def test(self):
28        # Test parameters.
29        LL_scanner_scanInterval_MIN = 0x2000
30        LL_scanner_scanInterval_MAX = 0x2000
31        LL_scanner_scanWindow_MIN = 0x200
32        LL_scanner_scanWindow_MAX = 0x200
33        LL_scanner_Adv_Channel_Map = 0x7
34
35        controller = self.controller
36        peer_address = Address('aa:bb:cc:dd:ee:ff')
37
38        controller.send_cmd(
39            hci.LeSetScanParameters(le_scan_type=hci.LeScanType.ACTIVE,
40                                    le_scan_interval=LL_scanner_scanInterval_MAX,
41                                    le_scan_window=LL_scanner_scanWindow_MAX,
42                                    own_address_type=hci.OwnAddressType.RESOLVABLE_OR_PUBLIC_ADDRESS,
43                                    scanning_filter_policy=hci.LeScanningFilterPolicy.ACCEPT_ALL))
44
45        await self.expect_evt(hci.LeSetScanParametersComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1))
46
47        controller.send_cmd(
48            hci.LeSetScanEnable(le_scan_enable=hci.Enable.ENABLED, filter_duplicates=hci.Enable.DISABLED))
49
50        await self.expect_evt(hci.LeSetScanEnableComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1))
51
52        controller.send_ll(ll.LeLegacyAdvertisingPdu(source_address=peer_address,
53                                                     advertising_address_type=ll.AddressType.RANDOM,
54                                                     advertising_type=ll.LegacyAdvertisingType.ADV_SCAN_IND,
55                                                     advertising_data=[]),
56                           rssi=-16)
57
58        await self.expect_evt(
59            hci.LeAdvertisingReport(responses=[
60                hci.LeAdvertisingResponse(event_type=hci.AdvertisingEventType.ADV_SCAN_IND,
61                                          address_type=hci.AddressType.RANDOM_DEVICE_ADDRESS,
62                                          address=peer_address,
63                                          advertising_data=[],
64                                          rssi=0xf0)
65            ]))
66
67        await self.expect_ll(
68            ll.LeScan(source_address=controller.address,
69                      destination_address=peer_address,
70                      advertising_address_type=ll.AddressType.RANDOM,
71                      scanning_address_type=ll.AddressType.PUBLIC))
72
73        # Disable the scanner before the scan response is received.
74        controller.send_cmd(hci.LeSetScanEnable(le_scan_enable=hci.Enable.DISABLED))
75
76        await self.expect_evt(hci.LeSetScanEnableComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1))
77
78        # Send the scan response now; it should be ignored by the disabled scanner.
79        controller.send_ll(ll.LeScanResponse(source_address=peer_address,
80                                             advertising_address_type=ll.AddressType.RANDOM,
81                                             scan_response_data=[]),
82                           rssi=-16)
83
84        # Re-enable the scanner and send the advertising PDU again.
85        # This time expect the scan response to be properly reported.
86        controller.send_cmd(
87            hci.LeSetScanEnable(le_scan_enable=hci.Enable.ENABLED, filter_duplicates=hci.Enable.DISABLED))
88
89        await self.expect_evt(hci.LeSetScanEnableComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1))
90
91        controller.send_ll(ll.LeLegacyAdvertisingPdu(source_address=peer_address,
92                                                     advertising_address_type=ll.AddressType.RANDOM,
93                                                     advertising_type=ll.LegacyAdvertisingType.ADV_SCAN_IND,
94                                                     advertising_data=[]),
95                           rssi=-16)
96
97        await self.expect_evt(
98            hci.LeAdvertisingReport(responses=[
99                hci.LeAdvertisingResponse(event_type=hci.AdvertisingEventType.ADV_SCAN_IND,
100                                          address_type=hci.AddressType.RANDOM_DEVICE_ADDRESS,
101                                          address=peer_address,
102                                          advertising_data=[],
103                                          rssi=0xf0)
104            ]))
105
106        await self.expect_ll(
107            ll.LeScan(source_address=controller.address,
108                      destination_address=peer_address,
109                      advertising_address_type=ll.AddressType.RANDOM,
110                      scanning_address_type=ll.AddressType.PUBLIC))
111
112        controller.send_ll(ll.LeScanResponse(source_address=peer_address,
113                                             advertising_address_type=ll.AddressType.RANDOM,
114                                             scan_response_data=[]),
115                           rssi=-16)
116
117        await self.expect_evt(
118            hci.LeAdvertisingReport(responses=[
119                hci.LeAdvertisingResponse(event_type=hci.AdvertisingEventType.SCAN_RESPONSE,
120                                          address_type=hci.AddressType.RANDOM_DEVICE_ADDRESS,
121                                          address=peer_address,
122                                          advertising_data=[],
123                                          rssi=0xf0)
124            ]))
125