Skip to content

Bluetooth: att: fix retry check swallowing non-security ATT errors - #57

Open
nktn wants to merge 1 commit into
zmkfirmware:v3.5.0+zmk-fixesfrom
nktn:v3.5.0+zmk-fixes-att-sec-err
Open

Bluetooth: att: fix retry check swallowing non-security ATT errors#57
nktn wants to merge 1 commit into
zmkfirmware:v3.5.0+zmk-fixesfrom
nktn:v3.5.0+zmk-fixes-att-sec-err

Conversation

@nktn

@nktn nktn commented Jul 31, 2026

Copy link
Copy Markdown

Summary

This fixes an incorrect return-value type in 339570e ("bluetooth: att: Properly
retry on errors mid-encryption.") on the v3.5.0+zmk-fixes branch.

That commit addresses a real race — an ATT error can arrive while a
security upgrade is already in progress, and the request should still be
retried in that case. Upstream Zephyr later made the same improvement in
v3.6.0, so the intent matches where upstream ended up as well.

The implementation stores att_change_security()'s int return value
(which can be -EINVAL, -EALREADY, -EBUSY, or an error from
bt_conn_set_security()) in a uint8_t:

uint8_t set_sec_err;

set_sec_err = att_change_security(chan->chan.chan.conn, err);
if (set_sec_err >= 0 || set_sec_err == -EBUSY) {

Since a uint8_t is never negative, set_sec_err >= 0 is always true,
so every ATT error response handled by this path is treated as retryable.
the ATT timeout is cancelled, the request is marked retrying, and
att_handle_rsp() is never called. For errors that security elevation
cannot fix — e.g. 0x0a Attribute Not Found at the end of a GATT
discovery — no security-change event will ever arrive, so the request
hangs forever and the GATT callback never fires.

For comparison: v3.6.0+ has the same mid-encryption improvement but
keeps the return value in an int (ret == 0 || ret == -EBUSY), while
vanilla v3.5.0 retries only on 0. Neither exhibits the hang — only
this branch's uint8_t variant does.

Fix

Use int and check == 0 || == -EBUSY, matching upstream v3.6.0+
(att_error_rsp() in subsys/bluetooth/host/att.c). This keeps the
mid-encryption retry behavior the original commit introduced, while
letting non-recoverable errors reach att_handle_rsp() again.

Two-line change; no behavioral difference for the genuine
security-retry cases (0 / -EBUSY).

Commit 339570e ("bluetooth: att: Properly retry on errors
mid-encryption.") changed the CONFIG_BT_ATT_RETRY_ON_SEC_ERR check to
also retry while a security upgrade is in progress, but stored
att_change_security()'s int return value in a uint8_t. As a result
set_sec_err >= 0 is always true and == -EBUSY can never match: every
ATT error response on a pending request (e.g. 0x0a Attribute Not Found
at the end of a GATT discovery) cancels the ATT timeout, marks the
request as retrying and never reaches att_handle_rsp(), so GATT client
requests hang forever whenever the server returns an error that
security elevation cannot fix.

Use int and check == 0 || == -EBUSY, matching upstream Zephyr v3.6.0+
(att_error_rsp() in subsys/bluetooth/host/att.c).

Signed-off-by: Fumihiko Nakatani <cube35@live.jp>
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