diff --git a/bumble/device.py b/bumble/device.py index 5dd23bf..1ffc5c6 100644 --- a/bumble/device.py +++ b/bumble/device.py @@ -46,6 +46,7 @@ from .hci import ( HCI_LE_CODED_PHY_LE_SUPPORTED_FEATURE, HCI_LE_EXTENDED_ADVERTISING_LE_SUPPORTED_FEATURE, HCI_LE_EXTENDED_CREATE_CONNECTION_COMMAND, + HCI_LE_RAND_COMMAND, HCI_LE_READ_PHY_COMMAND, HCI_MITM_NOT_REQUIRED_GENERAL_BONDING_AUTHENTICATION_REQUIREMENTS, HCI_MITM_NOT_REQUIRED_NO_BONDING_AUTHENTICATION_REQUIREMENTS, @@ -78,6 +79,7 @@ from .hci import ( HCI_LE_Enable_Encryption_Command, HCI_LE_Extended_Advertising_Report_Event, HCI_LE_Extended_Create_Connection_Command, + HCI_LE_Rand_Command, HCI_LE_Read_PHY_Command, HCI_LE_Set_Advertising_Data_Command, HCI_LE_Set_Advertising_Enable_Command, @@ -1113,10 +1115,35 @@ class Device(CompositeEventEmitter): if self.le_enabled: # Set the controller address - await self.send_command( - HCI_LE_Set_Random_Address_Command(random_address=self.random_address), - check_result=True, - ) + if self.random_address == Address.ANY_RANDOM: + # Try to use an address generated at random by the controller + if self.host.supports_command(HCI_LE_RAND_COMMAND): + # Get 8 random bytes + response = await self.send_command( + HCI_LE_Rand_Command(), check_result=True + ) + + # Ensure the address bytes can be a static random address + address_bytes = response.return_parameters.random_number[ + :5 + ] + bytes([response.return_parameters.random_number[5] | 0xC0]) + + # Create a static random address from the random bytes + self.random_address = Address(address_bytes) + + if self.random_address != Address.ANY_RANDOM: + logger.debug( + color( + f'LE Random Address: {self.random_address}', + 'yellow', + ) + ) + await self.send_command( + HCI_LE_Set_Random_Address_Command( + random_address=self.random_address + ), + check_result=True, + ) # Load the address resolving list if self.keystore and self.host.supports_command( diff --git a/bumble/hci.py b/bumble/hci.py index 257b303..b721700 100644 --- a/bumble/hci.py +++ b/bumble/hci.py @@ -1638,8 +1638,8 @@ class HCI_Object: # Map the value if needed if value_mappers: value_mapper = value_mappers.get(key, value_mapper) - if value_mapper is not None: - value = value_mapper(value) + if value_mapper is not None: + value = value_mapper(value) # Get the string representation of the value value_str = HCI_Object.format_field_value( @@ -1807,6 +1807,7 @@ class Address: # Predefined address values Address.NIL = Address(b"\xff\xff\xff\xff\xff\xff", Address.PUBLIC_DEVICE_ADDRESS) Address.ANY = Address(b"\x00\x00\x00\x00\x00\x00", Address.PUBLIC_DEVICE_ADDRESS) +Address.ANY_RANDOM = Address(b"\x00\x00\x00\x00\x00\x00", Address.RANDOM_DEVICE_ADDRESS) # ----------------------------------------------------------------------------- class OwnAddressType: @@ -3104,6 +3105,16 @@ class HCI_LE_Read_Remote_Features_Command(HCI_Command): ''' +# ----------------------------------------------------------------------------- +@HCI_Command.command( + return_parameters_fields=[("status", STATUS_SPEC), ("random_number", 8)] +) +class HCI_LE_Rand_Command(HCI_Command): + """ + See Bluetooth spec @ 7.8.23 LE Rand Command + """ + + # ----------------------------------------------------------------------------- @HCI_Command.command( [