Skip to content

Conversation

@jegt
Copy link

@jegt jegt commented Jan 24, 2026

Summary

Fix the setEvent() method in CInterop.HCIFilterSocketOption to correctly handle HCI events with codes >= 32.

Problem

The current implementation always sets bits in eventMask.0, even for events >= 32. The HCI filter structure uses two 32-bit event mask words:

  • eventMask.0 for events 0-31
  • eventMask.1 for events 32-63

For LE Meta Event (code 0x3E = 62):

  • bit = 62 & 63 = 62
  • HCISetBit(62, &eventMask.0) attempts to set bit 62 in a 32-bit integer

This results in the LE Meta events being filtered out by the kernel, making all BLE scanning non-functional.

Symptoms

  • lowEnergyScan() returns a valid AsyncLowEnergyScanStream
  • The stream never yields any scan results
  • No errors are thrown
  • btmon shows LE Advertising Reports ARE being received by the kernel

Verification

Tested on Linux 6.8.0-90-generic (Ubuntu 24.04) with Realtek USB Bluetooth adapter. After the fix, scanning correctly discovers BLE devices:

device_discovered: A8:03:2A:B9:FE:FA (ShellyPlus1-A8032AB9FEF8)
device_discovered: C4:82:E1:06:93:C7 (TY)
device_discovered: 4A:F4:13:64:66:50 (Quest 3)
device_discovered: DD:DF:30:71:BB:06 (Ruuvi BB06)

Possibly Related

This may be related to #40 - while that issue reports a different error, the underlying cause (improper HCI filter configuration) is similar.

jegt added 2 commits January 24, 2026 17:46
The setEvent() method always set bits in eventMask.0, even for events
with codes >= 32. The HCI filter structure uses two 32-bit event mask
words: eventMask.0 for events 0-31 and eventMask.1 for events 32-63.

For LE Meta Event (code 0x3E = 62), this meant bit 30 was incorrectly
set in eventMask.0 instead of eventMask.1, causing the kernel to filter
out all LE Meta events. This made BLE scanning non-functional - the
stream would be created successfully but never yield any results.

The fix routes events >= 32 to eventMask.1 with the appropriate bit offset.

Tested on Linux 6.8 with Realtek USB Bluetooth adapter - scanning now
correctly discovers BLE devices.
The lowEnergyClient() method was returning immediately after starting
a non-blocking connect, without waiting for the connection to actually
complete. For non-blocking sockets, connect() returns EINPROGRESS and
the caller must poll for writability to know when the connection is
established.

This caused GATT operations to fail because the socket wasn't actually
connected when the GATT client tried to use it.

The fix:
1. Catches EINPROGRESS from the non-blocking connect
2. Polls for writability with a 30 second timeout
3. Checks for error/hangup events indicating connection failure
4. Only returns the socket once the connection is confirmed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant