Skip to content

HID OUTPUT reports silently dropped when host sends fewer bytes than descriptor size #721

@mitchellcairns

Description

@mitchellcairns

Component: src/classic/hid_device.c
Affected function: hid_report_size_valid() (permalink)

Description

Some Bluetooth HID hosts send OUTPUT (or FEATURE) reports that are equal to or shorter than the report size defined in the HID descriptor. This is observed in practice with certain host operating systems and HID implementations that omit trailing zero-padded bytes.

The current validation logic in hid_report_size_valid() performs a strict equality check:

if ((size == 0) || (size != report_size)) return 0;

This causes any report whose size does not exactly match the descriptor-defined size to be silently dropped. No callback is fired, no HCI event is emitted, and user-space code has no way to know the report was received and discarded.

Why this is a problem

  • The HID specification is often not strictly defined on many hosts; shorter reports (with implicit trailing zeros) are a reasonable and observed real-world behavior.
  • The failure mode is silent. From the application's perspective, the host appears to not be sending any OUTPUT reports at all.
  • The report size is already passed as a parameter when the callback is fired, so user-space code is fully capable of handling size validation or tolerating short reports itself, it doesn't need BTStack to silently discard them.

Suggested fix

Relax the strict equality check to allow reports that are less than or equal to the descriptor size:

// Before
if ((size == 0) || (size != report_size)) return 0;

// After
if ((size == 0) || (report_size > size)) return 0;

This would pass through reports that are shorter than the descriptor size while still rejecting reports that are larger (which are more likely to indicate a genuine protocol error).

Alternative: opt-in permissive mode

If relaxing the check unconditionally is undesirable, a compile-time flag or runtime option (e.g. hid_device_set_report_size_strict(bool)), or btstack_config header parameter could allow applications to opt in to permissive size validation, deferring the size check to user-space where the report size parameter is already available.

Steps to reproduce

  1. Set up a BTStack HID device (e.g. keyboard or custom HID class).
  2. Connect from a host that sends OUTPUT reports shorter than the full descriptor-defined report size (observed on certain Windows and Linux HID drivers).
  3. Observe that no OUTPUT report callback is triggered in user-space despite the host transmitting reports.

Expected behavior

Reports that are less than or equal to the descriptor size should be delivered to user-space, with the actual received size passed in the callback so the application can handle them appropriately.

Actual behavior

Reports with report_size < descriptor_size are silently dropped inside hid_report_size_valid() with no notification to the application.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions