You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
dongle: dead client is never reaped after failed GIP handshake — occupied slot freezes pairing scan, controller can never reconnect or pair (permanent wedge until replug) #210
Dongle: Microsoft Xbox Wireless Adapter (045e:02e6), official, behind a USB 2.0 hub
Controller: Xbox Elite Series 2 (045e:0b00, firmware 5.22.16.0)
USB autosuspend disabled (usbcore.autosuspend=-1), TLP inactive
Summary
If a controller associates with the dongle but the GIP handshake fails to complete (e.g. because the pairing channel scan switches channels mid-handshake, or during the unstable post-firmware-load window at boot), the half-created client stays in the dongle's client table forever. The driver has no mechanism to reap it, and the occupied slot then freezes the pairing channel scan (xone_dongle_pairing_scan skips hopping when client_count > 0 — dongle.c:346 in 0.5.8). The dongle sits on one fixed channel indefinitely, so the controller can neither reconnect with its stored pairing nor re-pair via the sync button. The wedge is permanent until the driver instance is destroyed (physical replug or authorized 0/1 power-cycle).
The poweroff sysfs attribute cannot clear the ghost either: it sends a power-off packet to a client that is no longer listening, then xone_dongle_power_off_clients waits for client_count to reach 0 and returns -ETIMEDOUT. The slot stays occupied.
Observed wedged state
…:1.0/gip0 exists (radio up), pairing reads 0
active_clients reads Active clients: 1 with slot [00]* occupied
Nogip0.* child devices under gip0/, no input device, no gip events in dmesg
Sync-button pairing always fails: controller flashes fast, dongle reacts, controller falls back to slow flash. With dynamic debug enabled there are zeroxone_dongle_pairing_scan: channel switch lines while pairing — the scan never hops because of the occupied slot.
Controller associates; occasionally the GIP handshake breaks (my guess: a channel switch lands between association and handshake completion — the exact race described in the comment above the client_count guard in xone_dongle_pairing_scan).
Controller gives up (slow flash). Dongle keeps the dead client forever → wedged as above.
Not deterministic, but on my system it happened on roughly every second boot/replug with the controller already on. 100% avoidable by keeping the controller off until the firmware load settles, which supports the mid-load-race explanation.
Healthy trace for comparison (dynamic debug)
With the controller off during the power-cycle, everything works — stored pairing intact, no sync needed:
In the wedged state the ADD_CLIENT happened at some earlier point but the announce/handshake never completed, and nothing ever cleans up.
Suggested fixes
Reap clients whose GIP handshake does not complete within a timeout (a few seconds after ADD_CLIENT without a completed announce → remove client, decrement client_count). This directly unfreezes the pairing scan.
Additionally/alternatively: let poweroff (or a new sysfs attribute) force-remove a slot locally when the client does not respond, instead of returning -ETIMEDOUT and keeping the slot.
Possibly related: #195 (association succeeds, handshake stalls after auto-sleep — different trigger, but the "half-connected client" state looks like the same underlying gap).
System
xone-dkms-git), DKMS build matches running kernelusbcore.autosuspend=-1), TLP inactiveSummary
If a controller associates with the dongle but the GIP handshake fails to complete (e.g. because the pairing channel scan switches channels mid-handshake, or during the unstable post-firmware-load window at boot), the half-created client stays in the dongle's client table forever. The driver has no mechanism to reap it, and the occupied slot then freezes the pairing channel scan (
xone_dongle_pairing_scanskips hopping whenclient_count > 0— dongle.c:346 in 0.5.8). The dongle sits on one fixed channel indefinitely, so the controller can neither reconnect with its stored pairing nor re-pair via the sync button. The wedge is permanent until the driver instance is destroyed (physical replug orauthorized0/1 power-cycle).The
poweroffsysfs attribute cannot clear the ghost either: it sends a power-off packet to a client that is no longer listening, thenxone_dongle_power_off_clientswaits forclient_countto reach 0 and returns-ETIMEDOUT. The slot stays occupied.Observed wedged state
…:1.0/gip0exists (radio up),pairingreads 0active_clientsreadsActive clients: 1with slot[00]*occupiedgip0.*child devices undergip0/, no input device, no gip events in dmesgxone_dongle_pairing_scan: channel switchlines while pairing — the scan never hops because of the occupied slot.echo -1 > poweroff→tee: … Connection timed out, slot still occupiedHow the ghost gets created (reproduction)
client_countguard inxone_dongle_pairing_scan).Not deterministic, but on my system it happened on roughly every second boot/replug with the controller already on. 100% avoidable by keeping the controller off until the firmware load settles, which supports the mid-load-race explanation.
Healthy trace for comparison (dynamic debug)
With the controller off during the power-cycle, everything works — stored pairing intact, no sync needed:
In the wedged state the ADD_CLIENT happened at some earlier point but the announce/handshake never completed, and nothing ever cleans up.
Suggested fixes
client_count). This directly unfreezes the pairing scan.poweroff(or a new sysfs attribute) force-remove a slot locally when the client does not respond, instead of returning-ETIMEDOUTand keeping the slot.Possibly related: #195 (association succeeds, handshake stalls after auto-sleep — different trigger, but the "half-connected client" state looks like the same underlying gap).