From 27a6f0a441c14a76717ae1d7795bc6d5a3939afd Mon Sep 17 00:00:00 2001 From: Gilles Boccon-Gibod Date: Fri, 23 Jan 2026 21:35:28 -0800 Subject: [PATCH] fix a few HCI types and make the bridge more robust --- apps/hci_bridge.py | 4 +++- bumble/bridge.py | 7 ++++++- bumble/device.py | 6 +++--- bumble/hci.py | 40 ++++++++++++++++++++++------------------ 4 files changed, 34 insertions(+), 23 deletions(-) diff --git a/apps/hci_bridge.py b/apps/hci_bridge.py index e50d4051..4114bf44 100644 --- a/apps/hci_bridge.py +++ b/apps/hci_bridge.py @@ -81,7 +81,9 @@ def host_to_controller_filter(hci_packet): response = hci.HCI_Command_Complete_Event( num_hci_command_packets=1, command_opcode=hci_packet.op_code, - return_parameters=bytes([hci.HCI_SUCCESS]), + return_parameters=hci.HCI_StatusReturnParameters( + status=hci.HCI_ErrorCode.SUCCESS + ), ) # Return a packet with 'respond to sender' set to True return (bytes(response), True) diff --git a/bumble/bridge.py b/bumble/bridge.py index 27ff3abd..168f7734 100644 --- a/bumble/bridge.py +++ b/bumble/bridge.py @@ -37,7 +37,12 @@ def __init__(self, hci_sink, sender_hci_sink, packet_filter, trace): def on_packet(self, packet): # Convert the packet bytes to an object - hci_packet = HCI_Packet.from_bytes(packet) + try: + hci_packet = HCI_Packet.from_bytes(packet) + except Exception: + logger.warning('forwarding unparsed packet as-is') + self.hci_sink.on_packet(packet) + return # Filter the packet if self.packet_filter is not None: diff --git a/bumble/device.py b/bumble/device.py index 89e9a6f2..8ac99897 100644 --- a/bumble/device.py +++ b/bumble/device.py @@ -1177,7 +1177,7 @@ class ChannelSoundingCapabilities: rtt_capability: int rtt_aa_only_n: int rtt_sounding_n: int - rtt_random_payload_n: int + rtt_random_sequence_n: int nadm_sounding_capability: int nadm_random_capability: int cs_sync_phys_supported: int @@ -2836,7 +2836,7 @@ async def power_on(self) -> None: rtt_capability=result.rtt_capability, rtt_aa_only_n=result.rtt_aa_only_n, rtt_sounding_n=result.rtt_sounding_n, - rtt_random_payload_n=result.rtt_random_payload_n, + rtt_random_sequence_n=result.rtt_random_sequence_n, nadm_sounding_capability=result.nadm_sounding_capability, nadm_random_capability=result.nadm_random_capability, cs_sync_phys_supported=result.cs_sync_phys_supported, @@ -6300,7 +6300,7 @@ def on_cs_remote_supported_capabilities( rtt_capability=event.rtt_capability, rtt_aa_only_n=event.rtt_aa_only_n, rtt_sounding_n=event.rtt_sounding_n, - rtt_random_payload_n=event.rtt_random_payload_n, + rtt_random_sequence_n=event.rtt_random_sequence_n, nadm_sounding_capability=event.nadm_sounding_capability, nadm_random_capability=event.nadm_random_capability, cs_sync_phys_supported=event.cs_sync_phys_supported, diff --git a/bumble/hci.py b/bumble/hci.py index 11ba83ce..7e253db5 100644 --- a/bumble/hci.py +++ b/bumble/hci.py @@ -2379,24 +2379,28 @@ class HCI_Packet: @classmethod def from_bytes(cls, packet: bytes) -> HCI_Packet: - packet_type = packet[0] + try: + packet_type = packet[0] - if packet_type == HCI_COMMAND_PACKET: - return HCI_Command.from_bytes(packet) + if packet_type == HCI_COMMAND_PACKET: + return HCI_Command.from_bytes(packet) - if packet_type == HCI_ACL_DATA_PACKET: - return HCI_AclDataPacket.from_bytes(packet) + if packet_type == HCI_ACL_DATA_PACKET: + return HCI_AclDataPacket.from_bytes(packet) - if packet_type == HCI_SYNCHRONOUS_DATA_PACKET: - return HCI_SynchronousDataPacket.from_bytes(packet) + if packet_type == HCI_SYNCHRONOUS_DATA_PACKET: + return HCI_SynchronousDataPacket.from_bytes(packet) - if packet_type == HCI_EVENT_PACKET: - return HCI_Event.from_bytes(packet) + if packet_type == HCI_EVENT_PACKET: + return HCI_Event.from_bytes(packet) - if packet_type == HCI_ISO_DATA_PACKET: - return HCI_IsoDataPacket.from_bytes(packet) + if packet_type == HCI_ISO_DATA_PACKET: + return HCI_IsoDataPacket.from_bytes(packet) - return HCI_CustomPacket(packet) + return HCI_CustomPacket(packet) + except Exception as e: + logger.error(f'error parsing HCI packet [{packet.hex()}]: {e}') + raise def __init__(self, name: str) -> None: self.name = name @@ -5796,7 +5800,7 @@ class HCI_LE_Subrate_Request_Command(HCI_AsyncCommand): # ----------------------------------------------------------------------------- @dataclasses.dataclass -class HHCI_LE_CS_Read_Local_Supported_Capabilities_ReturnParameters( +class HCI_LE_CS_Read_Local_Supported_Capabilities_ReturnParameters( HCI_StatusReturnParameters ): num_config_supported: int = field(metadata=metadata(1)) @@ -5808,7 +5812,7 @@ class HHCI_LE_CS_Read_Local_Supported_Capabilities_ReturnParameters( rtt_capability: int = field(metadata=metadata(1)) rtt_aa_only_n: int = field(metadata=metadata(1)) rtt_sounding_n: int = field(metadata=metadata(1)) - rtt_random_payload_n: int = field(metadata=metadata(1)) + rtt_random_sequence_n: int = field(metadata=metadata(1)) nadm_sounding_capability: int = field(metadata=metadata(2)) nadm_random_capability: int = field(metadata=metadata(2)) cs_sync_phys_supported: int = field(metadata=metadata(CS_SYNC_PHY_SUPPORTED_SPEC)) @@ -5822,11 +5826,11 @@ class HHCI_LE_CS_Read_Local_Supported_Capabilities_ReturnParameters( @HCI_SyncCommand.sync_command( - HHCI_LE_CS_Read_Local_Supported_Capabilities_ReturnParameters + HCI_LE_CS_Read_Local_Supported_Capabilities_ReturnParameters ) @dataclasses.dataclass class HCI_LE_CS_Read_Local_Supported_Capabilities_Command( - HCI_SyncCommand[HHCI_LE_CS_Read_Local_Supported_Capabilities_ReturnParameters] + HCI_SyncCommand[HCI_LE_CS_Read_Local_Supported_Capabilities_ReturnParameters] ): ''' See Bluetooth spec @ 7.8.130 LE CS Read Local Supported Capabilities command @@ -5864,7 +5868,7 @@ class HCI_LE_CS_Write_Cached_Remote_Supported_Capabilities_Command( rtt_capability: int = field(metadata=metadata(1)) rtt_aa_only_n: int = field(metadata=metadata(1)) rtt_sounding_n: int = field(metadata=metadata(1)) - rtt_random_payload_n: int = field(metadata=metadata(1)) + rtt_random_sequence_n: int = field(metadata=metadata(1)) nadm_sounding_capability: int = field(metadata=metadata(2)) nadm_random_capability: int = field(metadata=metadata(2)) cs_sync_phys_supported: int = field(metadata=metadata(CS_SYNC_PHY_SUPPORTED_SPEC)) @@ -6986,7 +6990,7 @@ class HCI_LE_CS_Read_Remote_Supported_Capabilities_Complete_Event(HCI_LE_Meta_Ev rtt_capability: int = field(metadata=metadata(1)) rtt_aa_only_n: int = field(metadata=metadata(1)) rtt_sounding_n: int = field(metadata=metadata(1)) - rtt_random_payload_n: int = field(metadata=metadata(1)) + rtt_random_sequence_n: int = field(metadata=metadata(1)) nadm_sounding_capability: int = field(metadata=metadata(2)) nadm_random_capability: int = field(metadata=metadata(2)) cs_sync_phys_supported: int = field(metadata=metadata(CS_SYNC_PHY_SUPPORTED_SPEC))