From b70ebdef73e03ef9288bc26510c27b31c7d7394d Mon Sep 17 00:00:00 2001 From: Hui Peng Date: Tue, 21 Mar 2023 13:28:42 -0700 Subject: [PATCH 1/6] Allow Device.enable_classic to be configurable --- bumble/device.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bumble/device.py b/bumble/device.py index 512bb1d..eeab1c5 100644 --- a/bumble/device.py +++ b/bumble/device.py @@ -739,6 +739,7 @@ class DeviceConfiguration: self.le_enabled = True # LE host enable 2nd parameter self.le_simultaneous_enabled = True + self.classic_enabled = False self.classic_sc_enabled = True self.classic_ssp_enabled = True self.classic_accept_any = True @@ -768,6 +769,7 @@ class DeviceConfiguration: self.le_simultaneous_enabled = config.get( 'le_simultaneous_enabled', self.le_simultaneous_enabled ) + self.classic_enabled = config.get('classic_enabled', self.classic_enabled) self.classic_sc_enabled = config.get( 'classic_sc_enabled', self.classic_sc_enabled ) @@ -979,6 +981,7 @@ class Device(CompositeEventEmitter): self.keystore = KeyStore.create_for_device(config) self.irk = config.irk self.le_enabled = config.le_enabled + self.classic_enabled = config.classic_enabled self.le_simultaneous_enabled = config.le_simultaneous_enabled self.classic_ssp_enabled = config.classic_ssp_enabled self.classic_sc_enabled = config.classic_sc_enabled From d5c7d0db5718cc1a6c17a1cde4d62a2368c0c2a9 Mon Sep 17 00:00:00 2001 From: Hui Peng Date: Wed, 22 Mar 2023 13:26:04 -0700 Subject: [PATCH 2/6] Fix a bug in HCI_Object.dict_from_bytes --- bumble/hci.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bumble/hci.py b/bumble/hci.py index bcab7a7..083da81 100644 --- a/bumble/hci.py +++ b/bumble/hci.py @@ -1491,7 +1491,7 @@ class HCI_Object: elif field_type == -2: # 16-bit signed field_value = struct.unpack_from(' Date: Wed, 22 Mar 2023 00:37:34 -0700 Subject: [PATCH 3/6] Add implemenetation of HCI_PIN_Code_Request_Reply_Command --- bumble/hci.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/bumble/hci.py b/bumble/hci.py index 083da81..a8403b9 100644 --- a/bumble/hci.py +++ b/bumble/hci.py @@ -2097,6 +2097,24 @@ class HCI_Link_Key_Request_Negative_Reply_Command(HCI_Command): ''' +# ----------------------------------------------------------------------------- +@HCI_Command.command( + fields=[ + ('bd_addr', Address.parse_address), + ('pin_code_length', 1), + ('pin_code', '*'), + ], + return_parameters_fields=[ + ('status', STATUS_SPEC), + ('bd_addr', Address.parse_address), + ], +) +class HCI_PIN_Code_Request_Reply_Command(HCI_Command): + ''' + See Bluetooth spec @ 7.1.12 PIN Code Request Reply Command + ''' + + # ----------------------------------------------------------------------------- @HCI_Command.command( fields=[('bd_addr', Address.parse_address)], From 41d1772cb5ad47d01cb7bbd59c54a73d57504cb7 Mon Sep 17 00:00:00 2001 From: Hui Peng Date: Wed, 22 Mar 2023 00:38:16 -0700 Subject: [PATCH 4/6] Add test for HCI_PIN_Code_Request_Reply_Command --- tests/hci_test.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/hci_test.py b/tests/hci_test.py index 14e5182..6529885 100644 --- a/tests/hci_test.py +++ b/tests/hci_test.py @@ -52,6 +52,7 @@ from bumble.hci import ( HCI_LE_Set_Scan_Parameters_Command, HCI_Number_Of_Completed_Packets_Event, HCI_Packet, + HCI_PIN_Code_Request_Reply_Command, HCI_Read_Local_Supported_Commands_Command, HCI_Read_Local_Supported_Features_Command, HCI_Read_Local_Version_Information_Command, @@ -213,6 +214,17 @@ def test_HCI_Command(): # ----------------------------------------------------------------------------- +def test_HCI_PIN_Code_Request_Reply_Command(): + command = HCI_PIN_Code_Request_Reply_Command( + bd_addr=Address( + '00:11:22:33:44:55', address_type=Address.PUBLIC_DEVICE_ADDRESS + ), + pin_code_length=4, + pin_code=b'1234', + ) + basic_check(command) + + def test_HCI_Reset_Command(): command = HCI_Reset_Command() basic_check(command) @@ -440,6 +452,7 @@ def run_test_events(): def run_test_commands(): test_HCI_Command() test_HCI_Reset_Command() + test_HCI_PIN_Code_Request_Reply_Command() test_HCI_Read_Local_Version_Information_Command() test_HCI_Read_Local_Supported_Commands_Command() test_HCI_Read_Local_Supported_Features_Command() From afe87655085e928e91dd6abfddbe1f74abb766a4 Mon Sep 17 00:00:00 2001 From: Hui Peng Date: Wed, 22 Mar 2023 00:38:53 -0700 Subject: [PATCH 5/6] Add on_pin_code_request to support legacy BT classic pairing --- bumble/device.py | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/bumble/device.py b/bumble/device.py index eeab1c5..09c9435 100644 --- a/bumble/device.py +++ b/bumble/device.py @@ -94,6 +94,8 @@ from .hci import ( HCI_LE_Set_Scan_Enable_Command, HCI_LE_Set_Scan_Parameters_Command, HCI_LE_Set_Scan_Response_Data_Command, + HCI_PIN_Code_Request_Reply_Command, + HCI_PIN_Code_Request_Negative_Reply_Command, HCI_Read_BD_ADDR_Command, HCI_Read_RSSI_Command, HCI_Reject_Connection_Request_Command, @@ -2765,6 +2767,51 @@ class Device(CompositeEventEmitter): ) ) + # [Classic only] + @host_event_handler + @with_connection_from_address + def on_pin_code_request(self, connection): + # classic legacy pairing + # Ask what the pairing config should be for this connection + pairing_config = self.pairing_config_factory(connection) + + can_input = pairing_config.delegate.io_capability in ( + smp.SMP_KEYBOARD_ONLY_IO_CAPABILITY, + smp.SMP_KEYBOARD_DISPLAY_IO_CAPABILITY, + ) + + # respond the pin code + if can_input: + + async def get_pin_code(): + pin_code = await connection.abort_on( + 'disconnection', pairing_config.delegate.get_number() + ) + + if pin_code is not None: + pin_code = bytes(str(pin_code).zfill(6)) + await self.host.send_command( + HCI_PIN_Code_Request_Reply_Command( + bd_addr=connection.peer_address, + pin_code_length=len(pin_code), + pin_code=pin_code, + ) + ) + else: + await self.host.send_command( + HCI_PIN_Code_Request_Negative_Reply_Command( + bd_addr=connection.peer_address + ) + ) + + asyncio.create_task(get_pin_code()) + else: + self.host.send_command_sync( + HCI_PIN_Code_Request_Negative_Reply_Command( + bd_addr=connection.peer_address + ) + ) + # [Classic only] @host_event_handler @with_connection_from_address From d4346c3c9b17f2cb802bf87bbbbcbc0b28350c89 Mon Sep 17 00:00:00 2001 From: Hui Peng Date: Wed, 22 Mar 2023 13:13:52 -0700 Subject: [PATCH 6/6] delegate the HCI_PIN_Code_Request event on host --- bumble/host.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/bumble/host.py b/bumble/host.py index 9f667a1..a38f1ff 100644 --- a/bumble/host.py +++ b/bumble/host.py @@ -53,7 +53,6 @@ from .hci import ( HCI_LE_Write_Suggested_Default_Data_Length_Command, HCI_Link_Key_Request_Negative_Reply_Command, HCI_Link_Key_Request_Reply_Command, - HCI_PIN_Code_Request_Negative_Reply_Command, HCI_Packet, HCI_Read_Buffer_Size_Command, HCI_Read_Local_Supported_Commands_Command, @@ -794,11 +793,7 @@ class Host(AbortableEventEmitter): ) def on_hci_pin_code_request_event(self, event): - # For now, just refuse all requests - # TODO: delegate the decision - self.send_command_sync( - HCI_PIN_Code_Request_Negative_Reply_Command(bd_addr=event.bd_addr) - ) + self.emit('pin_code_request', event.bd_addr) def on_hci_link_key_request_event(self, event): async def send_link_key():