Missed Wi-Fi Netlink Events: Resynchronize State Instead of Trusting an Old Callback
Use Wi-Fi notifications to request reconciliation, not as an infallible history from which current association can always be reconstructed. After event loss, reader restart or an interrupted state query, mark the affected view uncertain and obtain fresh supported state. Never let a delayed callback overwrite a newer observation merely because it was processed last.
This guide pins Linux 6.12 Generic Netlink and nl80211 behavior for a single-link infrastructure station. If NetworkManager or another supplicant manager owns the connection, prefer its supported state API and keep one ownership boundary. The direct-netlink procedure is for a diagnostic integration that actually needs kernel observations; it does not start a second connection manager.
Do not invent an event sequence from request IDs
The kernel’s 6.12 Netlink introduction describes nlmsg_seq as matching responses to requests. Asynchronous notifications use zero. Therefore, a gap in your own request numbers is not a missing Wi-Fi event detector, and a zero-sequence notification is not automatically stale. Keep request correlation separate from the application’s observation generation. Linux 6.12 Netlink message exchanges
The Linux manual explains that kernel-to-userspace notifications can be dropped when the receiving socket buffer fills. An ENOBUFS receive error requires resynchronization. Increasing buffers can reduce pressure but does not turn notifications into a durable event log; suppressing that error through NETLINK_NO_ENOBUFS also suppresses useful loss evidence. Linux netlink(7), reliability and socket options
Record loss, message truncation, malformed input, socket replacement and incomplete requests explicitly. Keep the last known state as historical evidence with its observation time, but do not continue presenting it as freshly confirmed. Event loss is not proof that the radio disconnected; it is proof that your state reconstruction is no longer trustworthy.
Query the state that answers the question
For the pinned station implementation, the scan-result dump can mark the actual current BSS with NL80211_BSS_STATUS_ASSOCIATED. An ordinary cached BSS entry without that status is only discovery information. Retrieving existing scan state is also different from issuing a new radio scan. Do not trigger disruptive scanning merely to read an association indicator. Linux 6.12 nl80211_send_bss() and nl80211_dump_scan()
First resolve the current interface identity and role, then use the relevant supported association/peer queries or the manager’s equivalent. Bind observations to the current namespace, device/interface lifetime and reader generation. A familiar interface name or recycled numeric index alone is not a durable identity across removal and recreation.
Association, address configuration and application reachability remain separate observations. A reconciled BSS status does not certify DNS, TLS or service delivery. Conversely, a healthy application exchange does not repair a corrupted local netlink cache.

Use a dirty-generation reconciliation loop
- Establish the current reader and subscriptions. Resolve the family and relevant groups through the supported library, subscribe before the baseline query, and start a new local reader generation after socket or daemon replacement.
- Mark relevant events as dirty. Coalesce them into a reconciliation request. Preserve diagnostic event details, but avoid blindly replaying a queued old disconnect after a newer snapshot. An event arriving later may prompt another query without becoming authoritative state itself.
- Start one correlated query. Save the reader generation, request sequence, interface identity and current dirty revision. Build its result in a bounded staging object; never expose partially accumulated dump rows as the complete state.
- Validate the terminal result. Require matching replies and complete successful termination. Reject truncation, parse failure, timeout, reported loss and an interrupted dump. Inspect every multipart message, including the terminal one.
- Check for intervening relevant change. If the reader/interface lifetime changed or the dirty revision advanced during the query, discard the candidate and request another bounded pass. Do not merge parts from different attempts.
- Publish a qualified observation. Commit the candidate with its collection interval and source. Schedule periodic refresh so a missed notification without a visible gap cannot preserve old state indefinitely.
The 6.12 documentation warns that dumps may be non-atomic and that NLM_F_DUMP_INTR can appear on any dump message, including NLMSG_DONE. Userspace should retry an interrupted dump. The absence of that flag does not make several separate family queries one global atomic snapshot. Linux 6.12 dump consistency
Use a bounded retry policy under continuous churn. If no coherent observation can be obtained within the product’s budget, expose “state updating” or “unknown” and retain diagnostics. Do not busy-loop indefinitely or force a disconnect just to simplify the UI. The maximum acceptable observation age belongs to the product requirement.
Be precise about what generations can reject
A local generation can reject work queued by an old socket owner or an obsolete request. It cannot add a missing kernel event identity retroactively. When event ordering is ambiguous, reconcile again instead of claiming that a local counter reconstructs the exact RF history. Subscription-before-query reduces an initialization race but does not eliminate every race or loss condition.
For a hypothetical monitor, query Q1 begins while associated to AP A. A relevant transition arrives, then Q1’s old result completes. Because its saved dirty revision no longer matches, Q1 is discarded. Q2 observes AP B and becomes the new bounded-age view. A later queued old notification causes another readback; it does not directly replace B with disconnected.
Test the reconciliation boundary independently
A Python 3.12.14 model exercised clean commit, change during a query, interrupted termination, stale request completion, reader restart, receive-loss invalidation and late-notification handling. The fixture models the application’s admission rules; it does not parse netlink bytes, open sockets or execute kernel queries.
Target qualification must add actual multipart parsing, library error propagation, truncation handling, interface recreation and controlled reader pauses. Check that error suppression is not hiding loss and that failed queries leave the view explicitly uncertain. Record both successful recovery and periods where consistency could not be established.
Release with an observation-age limit, bounded staging/retry resources, request and lifetime correlation, and a documented state source. That makes a missed callback a recoverable synchronization problem instead of a permanently false connection indicator.