From bd25cf27dfb86241c3eb2bcff70d1e6a50dad20a Mon Sep 17 00:00:00 2001 From: Hui Peng Date: Fri, 24 Mar 2023 11:29:38 -0700 Subject: [PATCH 1/4] Fix a misconfig of HCI_PIN_Code_Reply_Command The pin_code field is of fixed length of 16 bytes --- bumble/hci.py | 2 +- tests/hci_test.py | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/bumble/hci.py b/bumble/hci.py index a8403b94..9b5793d4 100644 --- a/bumble/hci.py +++ b/bumble/hci.py @@ -2102,7 +2102,7 @@ class HCI_Link_Key_Request_Negative_Reply_Command(HCI_Command): fields=[ ('bd_addr', Address.parse_address), ('pin_code_length', 1), - ('pin_code', '*'), + ('pin_code', 16), ], return_parameters_fields=[ ('status', STATUS_SPEC), diff --git a/tests/hci_test.py b/tests/hci_test.py index 65298851..af68e860 100644 --- a/tests/hci_test.py +++ b/tests/hci_test.py @@ -215,12 +215,18 @@ def test_HCI_Command(): # ----------------------------------------------------------------------------- def test_HCI_PIN_Code_Request_Reply_Command(): + pin_code = b'1234' + pin_code_length = len(pin_code) + # here to make the test pass, we need to + # pad pin_code, as HCI_Object.format_fields + # does not do it for us + padded_pin_code = pin_code + bytes(16 - pin_code_length) 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', + pin_code_length=pin_code_length, + pin_code=padded_pin_code, ) basic_check(command) From a8e61673d0abb5f2de37c6049ea6ab7a0e945eaa Mon Sep 17 00:00:00 2001 From: Hui Peng Date: Fri, 24 Mar 2023 11:31:05 -0700 Subject: [PATCH 2/4] Fix HCI_PIN_Code_Reply_Command in Device.on_pin_code_request --- bumble/device.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/bumble/device.py b/bumble/device.py index 51bbb282..8136ff4b 100644 --- a/bumble/device.py +++ b/bumble/device.py @@ -2808,11 +2808,23 @@ class Device(CompositeEventEmitter): ) if pin_code is not None: - pin_code = bytes(str(pin_code).zfill(6)) + # TODO: make pin code input more flexible, + # so far only numbers are allowed + pin_code = bytes(str(pin_code), encoding='utf8') + pin_code_len = len(pin_code) + if pin_code_len > 16: + logger.warning( + 'pin_code is longer than 16 bytes, truncated to 16' + ) + pin_code_len = 16 + # the pin_code will be truncated according to pin_code_len + # when converted to byte array in HCI_Object, so we + # are not doing truncation here + await self.host.send_command( HCI_PIN_Code_Request_Reply_Command( bd_addr=connection.peer_address, - pin_code_length=len(pin_code), + pin_code_length=pin_code_len, pin_code=pin_code, ) ) From 423a5a95d8bc8804235bdd73d0057d504b705449 Mon Sep 17 00:00:00 2001 From: Hui Peng Date: Sat, 25 Mar 2023 13:26:41 +0000 Subject: [PATCH 3/4] add get_string API in PairingDelegate --- bumble/smp.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/bumble/smp.py b/bumble/smp.py index 9a72cb0d..3af4895c 100644 --- a/bumble/smp.py +++ b/bumble/smp.py @@ -525,6 +525,12 @@ class PairingDelegate: async def get_number(self) -> int: return 0 + async def get_string(self, max_length) -> Optional[str]: + ''' + Returns a string whose utf-8 encoding is up to max_length bytes. + ''' + return None + # pylint: disable-next=unused-argument async def display_number(self, number: int, digits: int) -> None: pass From dcd66743f6f2efaded2ab1633dc6078b38edf7b9 Mon Sep 17 00:00:00 2001 From: Hui Peng Date: Sat, 25 Mar 2023 13:30:13 +0000 Subject: [PATCH 4/4] Use delegate.get_string to get pin code --- bumble/device.py | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/bumble/device.py b/bumble/device.py index 8136ff4b..5188448e 100644 --- a/bumble/device.py +++ b/bumble/device.py @@ -2804,23 +2804,13 @@ class Device(CompositeEventEmitter): async def get_pin_code(): pin_code = await connection.abort_on( - 'disconnection', pairing_config.delegate.get_number() + 'disconnection', pairing_config.delegate.get_string(16) ) if pin_code is not None: - # TODO: make pin code input more flexible, - # so far only numbers are allowed - pin_code = bytes(str(pin_code), encoding='utf8') + pin_code = bytes(pin_code, encoding='utf-8') pin_code_len = len(pin_code) - if pin_code_len > 16: - logger.warning( - 'pin_code is longer than 16 bytes, truncated to 16' - ) - pin_code_len = 16 - # the pin_code will be truncated according to pin_code_len - # when converted to byte array in HCI_Object, so we - # are not doing truncation here - + assert 0 < pin_code_len <= 16, "pin_code should be 1-16 bytes" await self.host.send_command( HCI_PIN_Code_Request_Reply_Command( bd_addr=connection.peer_address, @@ -2829,6 +2819,7 @@ class Device(CompositeEventEmitter): ) ) else: + logger.debug("delegate.get_string() returned None") await self.host.send_command( HCI_PIN_Code_Request_Negative_Reply_Command( bd_addr=connection.peer_address