The data_available() check in iso15693.c:1574 fires at any point during the DMA receive loop — including mid-frame while the reader is actively transmitting. When it fires during a CHECK response or during UPDATE transmission, the decoder exits early with -2, iclass.c drains the USB queue and continues — dropping the frame entirely. The reader times out waiting for a response, and restarts from READCHECK.
The fix is minimal: gate the data_available() check on the decoder being in STATE_READER_UNSYNCD (i.e., between frames, before SOF detection). Once SOF starts being received, the state transitions away from UNSYNCD and the check won't fire mid-frame.
Leveraging doMAC_brute for speed gains.
Precomputation (lines 330-346): Before the loop, sel_brute_idx[i] is set to the brute-byte index j if key_index[i] == bytes_to_recover[j], or 0xFF if that key_sel position is from a already-cracked constant entry. Fixed positions are filled into key_sel once here.
Hot loop (lines 356-361): Replaces:
numbytes_to_recover keytable writes + 8 keytable reads + 8 & 0xFF masks
With: up to numbytes_to_recover (1-3) direct shifts from brute — no keytable touches at all.
Success path (line 386): (brute >> (i * 8)) & 0xFF recovers the exact byte value that was just used for the winning iteration, equivalent to the old keytable[bytes_to_recover[i]] & 0xFF which was the same value that had just been written into the keytable from brute.
Optimized `hf iclass legbrute` throughput: replaced recursive `suc()`/`output()` cipher functions with iterative loops, added 256-entry LUT for the `select()` function eliminating redundant bit arithmetic and halving key lookups per state step, switched successor state to in-place pointer update removing per-call struct copies, added `doMAC_brute()` with byte-wise LSB-first processing and direct output bit packing eliminating all bitstream struct overhead and output reversal calls per key candidate, and replaced per-iteration 64-bit modulo progress check with a countdown counter
Improved `hf iclass legbrute`: fixed multithreaded key-range partitioning so threads cover non-overlapping slices of the 40-bit keyspace, added ETA display, keyboard abort with resume hint, `_Atomic` correctness for shared state, `pthread_create` error handling, and thread count capped at available CPUs .