From ff9b465ddb95d7842282998348df88ff55f62c4a Mon Sep 17 00:00:00 2001 From: Linmao Li Date: Fri, 7 Aug 2026 21:25:53 +0800 Subject: [PATCH 1/9] wifi: nxpwifi: protect sta_list against concurrent add and delete nxpwifi_del_sta_entry() unlinks an entry from priv->sta_list without holding priv->sta_list_spinlock. The comment above it gives the reason: the function is only reached from cfg80211_ops.del_station, which runs under the wiphy mutex. That mutex serialises this callback against other users of the same lock, including wiphy_work items. It covers neither of the two other writers of the same list: nxpwifi_add_sta_entry() from nxpwifi_uap_event_sta_assoc() nxpwifi_del_all_sta_list() from nxpwifi_uap_event_bss_idle() Both run from nxpwifi_process_event() on the driver's main work queue, a plain workqueue that never takes the wiphy lock, and both take sta_list_spinlock around their update. A station associating, or the BSS going idle, can therefore modify priv->sta_list while a hostapd del_station is walking it and unlinking an entry. Take the lock here too. As the traversal then runs under the write lock, list_for_each_entry() replaces the _rcu variant, matching nxpwifi_del_all_sta_list(). The same call path reaches nxpwifi_get_sta_entry() without rcu_read_lock(). Entries are freed with kfree_rcu() and every other caller holds it, so take it around the lookup as well. Fixes: 73b01e57ed3e ("wifi: nxp: add nxpwifi driver for IW61x") Signed-off-by: Linmao Li Tested-by: Jeff Chen Reviewed-by: Jeff Chen Signed-off-by: Jeff Chen --- drivers/net/wireless/nxp/nxpwifi/cfg80211.c | 2 ++ drivers/net/wireless/nxp/nxpwifi/util.c | 8 ++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/nxp/nxpwifi/cfg80211.c b/drivers/net/wireless/nxp/nxpwifi/cfg80211.c index 86304ea3331c..161697e038c0 100644 --- a/drivers/net/wireless/nxp/nxpwifi/cfg80211.c +++ b/drivers/net/wireless/nxp/nxpwifi/cfg80211.c @@ -1539,9 +1539,11 @@ nxpwifi_cfg80211_del_station(struct wiphy *wiphy, struct wireless_dev *wdev, eth_zero_addr(deauth_mac); + rcu_read_lock(); sta_node = nxpwifi_get_sta_entry(priv, params->mac); if (sta_node) ether_addr_copy(deauth_mac, params->mac); + rcu_read_unlock(); if (is_valid_ether_addr(deauth_mac)) { ret = nxpwifi_uap_sta_deauth(priv, deauth_mac); diff --git a/drivers/net/wireless/nxp/nxpwifi/util.c b/drivers/net/wireless/nxp/nxpwifi/util.c index bbfefb81d8d3..ae8444a14105 100644 --- a/drivers/net/wireless/nxp/nxpwifi/util.c +++ b/drivers/net/wireless/nxp/nxpwifi/util.c @@ -1041,19 +1041,23 @@ nxpwifi_set_sta_ht_cap(struct nxpwifi_private *priv, const u8 *ies, } } -/* Delete a station from list; called under cfg80211 mutex. */ +/* Delete a station from list. */ void nxpwifi_del_sta_entry(struct nxpwifi_private *priv, const u8 *mac) { struct nxpwifi_sta_node *node; - list_for_each_entry_rcu(node, &priv->sta_list, list) { + spin_lock_bh(&priv->sta_list_spinlock); + + list_for_each_entry(node, &priv->sta_list, list) { if (!memcmp(node->mac_addr, mac, ETH_ALEN)) { list_del_rcu(&node->list); kfree_rcu(node, rcu); break; } } + + spin_unlock_bh(&priv->sta_list_spinlock); } /* Delete all stations from list. */ From 128411832c62ca517e4abd938229f0ee40823fdb Mon Sep 17 00:00:00 2001 From: Linmao Li Date: Fri, 7 Aug 2026 21:25:54 +0800 Subject: [PATCH 2/9] wifi: nxpwifi: delete the station entry on the uAP deauth event When a station leaves, the firmware reports EVENT_UAP_STA_DEAUTH. nxpwifi_uap_event_sta_deauth() tears down the reorder, BA and WMM state for that peer but leaves its nxpwifi_sta_node on priv->sta_list. Nothing else removes it. cfg80211_del_sta() only reports the departure upwards, it does not call back into cfg80211_ops.del_station, and that callback is the only caller of nxpwifi_del_sta_entry(). The entry therefore survives until the BSS goes idle and nxpwifi_del_all_sta_list() drops everything. Until then the departed station still looks associated to the driver. nxpwifi_handle_uap_rx_forward() finds the stale node for that address, treats the frame as intra-BSS traffic and requeues it for transmission instead of passing it up the stack, so traffic for that address is misrouted. The list also keeps one entry per station that has ever associated, and a station that comes back reuses the stale node along with its old statistics. mwifiex, which nxpwifi was derived from, deletes the entry in the same event handler. Fixes: 73b01e57ed3e ("wifi: nxp: add nxpwifi driver for IW61x") Signed-off-by: Linmao Li Tested-by: Jeff Chen Reviewed-by: Jeff Chen Signed-off-by: Jeff Chen --- drivers/net/wireless/nxp/nxpwifi/uap_event.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/nxp/nxpwifi/uap_event.c b/drivers/net/wireless/nxp/nxpwifi/uap_event.c index ab5c15686f54..20b7b53db236 100644 --- a/drivers/net/wireless/nxp/nxpwifi/uap_event.c +++ b/drivers/net/wireless/nxp/nxpwifi/uap_event.c @@ -75,6 +75,7 @@ nxpwifi_uap_event_sta_deauth(struct nxpwifi_private *priv) nxpwifi_del_tx_ba_stream_tbl_by_ra(priv, deauth_mac); } nxpwifi_wmm_del_peer_ra_list(priv, deauth_mac); + nxpwifi_del_sta_entry(priv, deauth_mac); return 0; } From 5c9260d7c6990875fc788ebb86ea2bf08b492704 Mon Sep 17 00:00:00 2001 From: Linmao Li Date: Thu, 13 Aug 2026 16:23:13 +0800 Subject: [PATCH 3/9] wifi: nxpwifi: wait for the wakeup timer before the adapter is freed nxpwifi_adapter_cleanup() stops adapter->wakeup_timer with timer_delete(), which does not wait for a running callback. The callback goes on using the adapter: wakeup_timer_fn() sets adapter->hw_status, walks the command queues through nxpwifi_cancel_all_pending_cmd() and calls adapter->if_ops.card_reset(). Both paths that reach nxpwifi_adapter_cleanup() free the adapter right afterwards, through nxpwifi_free_adapter() in nxpwifi_remove_card() and in the nxpwifi_add_card() error unwind. Use timer_delete_sync() so the callback has finished before the adapter is released. mwifiex fixed the same issue in commit ae5e95d41574 ("wifi: mwifiex: fix use-after-free in mwifiex_adapter_cleanup()"). Fixes: 73b01e57ed3e ("wifi: nxp: add nxpwifi driver for IW61x") Signed-off-by: Linmao Li Reviewed-by: Jeff Chen Signed-off-by: Jeff Chen --- drivers/net/wireless/nxp/nxpwifi/init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/nxp/nxpwifi/init.c b/drivers/net/wireless/nxp/nxpwifi/init.c index 7c75dca5d0a8..3c4df37333d8 100644 --- a/drivers/net/wireless/nxp/nxpwifi/init.c +++ b/drivers/net/wireless/nxp/nxpwifi/init.c @@ -328,7 +328,7 @@ static void nxpwifi_invalidate_lists(struct nxpwifi_adapter *adapter) static void nxpwifi_adapter_cleanup(struct nxpwifi_adapter *adapter) { - timer_delete(&adapter->wakeup_timer); + timer_delete_sync(&adapter->wakeup_timer); nxpwifi_cancel_all_pending_cmd(adapter); wake_up_interruptible(&adapter->cmd_wait_q.wait); wake_up_interruptible(&adapter->hs_activate_wait_q); From d68d6d8d8bbb5596909479dc6cac58132d8f0dbf Mon Sep 17 00:00:00 2001 From: Linmao Li Date: Thu, 13 Aug 2026 16:23:14 +0800 Subject: [PATCH 4/9] wifi: nxpwifi: free the aggregation buffer when the RA list disappears nxpwifi_11n_aggregate_pkt() drops ra_list_spinlock while it copies each subframe, so it rechecks the RA list after taking the lock again. The check inside the aggregation loop returns without releasing the skb_aggr it has been filling, leaking one tx_buf_size buffer along with the subframes already aggregated into it. Release skb_aggr there, the way the same check on the -EBUSY path already does. mwifiex fixed the same issue in commit 990a73dec3fd ("wifi: mwifiex: Fix memory leak in mwifiex_11n_aggregate_pkt()"). Fixes: 73b01e57ed3e ("wifi: nxp: add nxpwifi driver for IW61x") Signed-off-by: Linmao Li Reviewed-by: Jeff Chen Signed-off-by: Jeff Chen --- drivers/net/wireless/nxp/nxpwifi/11n_aggr.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/nxp/nxpwifi/11n_aggr.c b/drivers/net/wireless/nxp/nxpwifi/11n_aggr.c index be7080f2a6ce..54933c42c960 100644 --- a/drivers/net/wireless/nxp/nxpwifi/11n_aggr.c +++ b/drivers/net/wireless/nxp/nxpwifi/11n_aggr.c @@ -168,6 +168,7 @@ nxpwifi_11n_aggregate_pkt(struct nxpwifi_private *priv, if (!nxpwifi_is_ralist_valid(priv, pra_list, ptrindex)) { spin_unlock_bh(&priv->wmm.ra_list_spinlock); + nxpwifi_write_data_complete(adapter, skb_aggr, 1, -1); return -ENOENT; } From 050f03bb0effd773c877cfba3b651c6d380b1c15 Mon Sep 17 00:00:00 2001 From: Linmao Li Date: Thu, 13 Aug 2026 16:23:15 +0800 Subject: [PATCH 5/9] wifi: nxpwifi: zero the channel statistics array adapter->chan_stats comes from vmalloc(), which does not clear the memory, and nxpwifi_cfg80211_dump_survey() reads it as soon as user space asks for survey data. For the entries no scan has filled in, a non-zero cca_scan_dur passes the validity check and stale bytes are reported to user space as noise, time and time_busy. Use kcalloc() instead. The array holds two entries per supported channel, small enough not to need vmalloc(), and the two callers change to kfree() accordingly. mwifiex fixed the same issue in commit 0e20450829ca ("wifi: mwifiex: Initialize the chan_stats array to zero"). Fixes: 73b01e57ed3e ("wifi: nxp: add nxpwifi driver for IW61x") Signed-off-by: Linmao Li Reviewed-by: Jeff Chen Signed-off-by: Jeff Chen --- drivers/net/wireless/nxp/nxpwifi/cfg80211.c | 5 +++-- drivers/net/wireless/nxp/nxpwifi/main.c | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/nxp/nxpwifi/cfg80211.c b/drivers/net/wireless/nxp/nxpwifi/cfg80211.c index 161697e038c0..788b83356981 100644 --- a/drivers/net/wireless/nxp/nxpwifi/cfg80211.c +++ b/drivers/net/wireless/nxp/nxpwifi/cfg80211.c @@ -3731,8 +3731,9 @@ int nxpwifi_init_channel_scan_gap(struct nxpwifi_adapter *adapter) * additional active scan request for hidden SSIDs on passive channels. */ adapter->num_in_chan_stats = 2 * (n_channels_bg + n_channels_a); - adapter->chan_stats = vmalloc(array_size(sizeof(*adapter->chan_stats), - adapter->num_in_chan_stats)); + adapter->chan_stats = kcalloc(adapter->num_in_chan_stats, + sizeof(*adapter->chan_stats), + GFP_KERNEL); if (!adapter->chan_stats) return -ENOMEM; diff --git a/drivers/net/wireless/nxp/nxpwifi/main.c b/drivers/net/wireless/nxp/nxpwifi/main.c index 55b962430f37..9e13348105c3 100644 --- a/drivers/net/wireless/nxp/nxpwifi/main.c +++ b/drivers/net/wireless/nxp/nxpwifi/main.c @@ -644,7 +644,7 @@ static int _nxpwifi_fw_dpc(const struct firmware *firmware, void *context) goto done; err_add_intf: - vfree(adapter->chan_stats); + kfree(adapter->chan_stats); err_init_chan_scan: wiphy_unregister(adapter->wiphy); wiphy_free(adapter->wiphy); @@ -1384,7 +1384,7 @@ static void nxpwifi_uninit_sw(struct nxpwifi_adapter *adapter) wiphy_free(adapter->wiphy); adapter->wiphy = NULL; - vfree(adapter->chan_stats); + kfree(adapter->chan_stats); nxpwifi_free_cmd_buffers(adapter); } From 7769bb2457fcfa8216aeae84f32cb7084cab5637 Mon Sep 17 00:00:00 2001 From: Linmao Li Date: Thu, 20 Aug 2026 16:16:33 +0800 Subject: [PATCH 6/9] wifi: nxpwifi: fix the authentication frame length handling nxpwifi_cfg80211_authenticate() builds a 3-address management frame in a temporary buffer and hands it to nxpwifi_form_mgmt_frame(), which copies it into the skb and splices in address4. The frame length is tracked in a single u16 that conflates the two lengths, and it gets both wrong. Truncation. req->ie_len and req->auth_data_len are both size_t. The IE policy caps req->ie_len at IEEE80211_MAX_DATA_LEN, but NL80211_ATTR_AUTH_DATA only has a four-byte minimum length policy. Since nla_len is a u16, a single authentication data attribute can carry up to 65531 bytes, enough for the combined frame length to exceed U16_MAX before it is assigned to pkt_len. With auth_data_len == 65510 and no IEs the length wraps to 6, kzalloc(6) succeeds, and the memcpy() below then writes 65506 user-provided bytes past a 6-byte heap object. Geometry. NXPWIFI_MGMT_HEADER_LEN is 30, which is the 24-byte 3-address header plus the address4 that the firmware expects. The temporary buffer only holds a struct ieee80211_hdr_3addr, so six of the bytes accounted for are never used, and passing that length to nxpwifi_form_mgmt_frame() makes it append ETH_ALEN on top of a length that already included it. The skb is sized without those six bytes, so the last skb_put_data() overruns the tailroom by exactly ETH_ALEN. It usually goes unnoticed because SKB_DATA_ALIGN() rounding leaves slack. The driver's other caller of the helper, nxpwifi_cfg80211_mgmt_tx(), adds ETH_ALEN to the skb size before allocating and passes the 3-address length, which is what this path should do too. Keep the two lengths apart. frame_len is the 3-address frame the driver builds: it sizes the temporary buffer and is what the helper is told. pkt_len is what the firmware sees, frame_len plus address4: it sizes the skb and goes into tx_info. Computing frame_len in size_t and rejecting anything that cannot be represented once ETH_ALEN is added removes the wrap. The value handed to the firmware is unchanged, so this is not a behavioural change for frames that were already valid. A tighter 802.11 bound may make sense, but that depends on the firmware's frame format and is a separate decision. Fixes: 73b01e57ed3e ("wifi: nxp: add nxpwifi driver for IW61x") Signed-off-by: Linmao Li Signed-off-by: Jeff Chen --- drivers/net/wireless/nxp/nxpwifi/cfg80211.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/nxp/nxpwifi/cfg80211.c b/drivers/net/wireless/nxp/nxpwifi/cfg80211.c index 788b83356981..3221ae167c58 100644 --- a/drivers/net/wireless/nxp/nxpwifi/cfg80211.c +++ b/drivers/net/wireless/nxp/nxpwifi/cfg80211.c @@ -3325,6 +3325,7 @@ nxpwifi_cfg80211_authenticate(struct wiphy *wiphy, struct nxpwifi_adapter *adapter = priv->adapter; struct sk_buff *skb; u16 pkt_len, auth_alg; + size_t frame_len; int ret; struct ieee80211_mgmt *mgmt; struct nxpwifi_txinfo *tx_info; @@ -3398,13 +3399,23 @@ nxpwifi_cfg80211_authenticate(struct wiphy *wiphy, nxpwifi_cancel_scan(adapter); - pkt_len = (u16)req->ie_len + req->auth_data_len + - NXPWIFI_MGMT_HEADER_LEN + NXPWIFI_AUTH_BODY_LEN; + frame_len = req->ie_len + req->auth_data_len + + sizeof(struct ieee80211_hdr_3addr) + NXPWIFI_AUTH_BODY_LEN; if (req->auth_data_len >= 4) - pkt_len -= 4; + frame_len -= 4; - mgmt = kzalloc(pkt_len, GFP_KERNEL); + /* nxpwifi_form_mgmt_frame() inserts address4, so the frame handed to + * the firmware is ETH_ALEN longer than the one built here. + */ + if (frame_len > U16_MAX - ETH_ALEN) { + nxpwifi_dbg(adapter, ERROR, + "auth frame too long: %zu bytes\n", frame_len); + return -EINVAL; + } + pkt_len = frame_len + ETH_ALEN; + + mgmt = kzalloc(frame_len, GFP_KERNEL); skb = dev_alloc_skb(NXPWIFI_MIN_DATA_HEADER_LEN + NXPWIFI_MGMT_FRAME_HEADER_SIZE + @@ -3450,7 +3461,7 @@ nxpwifi_cfg80211_authenticate(struct wiphy *wiphy, memcpy((u8 *)varptr, req->ie, req->ie_len); } - nxpwifi_form_mgmt_frame(skb, (const u8 *)mgmt, pkt_len); + nxpwifi_form_mgmt_frame(skb, (const u8 *)mgmt, frame_len); kfree(mgmt); priv->auth_flag = HOST_MLME_AUTH_PENDING; priv->auth_alg = auth_alg; From 7fa5fb9976c4532007a666624dc241021f74c8a9 Mon Sep 17 00:00:00 2001 From: Linmao Li Date: Thu, 20 Aug 2026 16:16:34 +0800 Subject: [PATCH 7/9] wifi: nxpwifi: handle authentication frame allocation failures nxpwifi_cfg80211_authenticate() allocates the buffer it builds the management frame in and never checks the result: mgmt = kzalloc(frame_len, GFP_KERNEL); skb = dev_alloc_skb(...); if (!skb) { ... return -ENOMEM; } ... memcpy(mgmt->da, req->bss->bssid, ETH_ALEN); On allocation failure the memcpy() a dozen lines later dereferences NULL. The same sequence leaks mgmt when dev_alloc_skb() fails: that path returns without freeing it, while the success path drops it after nxpwifi_form_mgmt_frame(). Bail out when the allocation fails, and free it before returning on the skb error path. Fixes: 73b01e57ed3e ("wifi: nxp: add nxpwifi driver for IW61x") Signed-off-by: Linmao Li Signed-off-by: Jeff Chen --- drivers/net/wireless/nxp/nxpwifi/cfg80211.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/nxp/nxpwifi/cfg80211.c b/drivers/net/wireless/nxp/nxpwifi/cfg80211.c index 3221ae167c58..473e81304ca8 100644 --- a/drivers/net/wireless/nxp/nxpwifi/cfg80211.c +++ b/drivers/net/wireless/nxp/nxpwifi/cfg80211.c @@ -3416,6 +3416,8 @@ nxpwifi_cfg80211_authenticate(struct wiphy *wiphy, pkt_len = frame_len + ETH_ALEN; mgmt = kzalloc(frame_len, GFP_KERNEL); + if (!mgmt) + return -ENOMEM; skb = dev_alloc_skb(NXPWIFI_MIN_DATA_HEADER_LEN + NXPWIFI_MGMT_FRAME_HEADER_SIZE + @@ -3423,6 +3425,7 @@ nxpwifi_cfg80211_authenticate(struct wiphy *wiphy, if (!skb) { nxpwifi_dbg(adapter, ERROR, "allocate skb failed for management frame\n"); + kfree(mgmt); return -ENOMEM; } From 32d1a000e99612e010335760363936d85591fd69 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Wed, 26 Aug 2026 00:17:09 +0100 Subject: [PATCH 8/9] wifi: nxpwifi: fix inverted check in Tx BA stream entry deletion nxpwifi_is_tx_ba_stream_ptr_valid() returns true when the entry is still linked, and every caller passes an entry that is on the list, so the early return always fires and nothing is ever unlinked or freed. Entries leak on every teardown and, since nxpwifi_space_avail_for_new_ba_stream() counts them, Tx aggregation stops being negotiated once the stale count reaches the maximum. Changing the original dead && test to || to silence a NULL dereference report inverted the validity test along with it. Fixes: 00c786a7581e ("wifi: nxpwifi: fix multiple static analysis errors and warnings") Assisted-by: Claude:claude-opus-5 Signed-off-by: David Carlier Signed-off-by: Jeff Chen --- drivers/net/wireless/nxp/nxpwifi/11n.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/nxp/nxpwifi/11n.c b/drivers/net/wireless/nxp/nxpwifi/11n.c index c2a54d781b42..25b2e430f3f9 100644 --- a/drivers/net/wireless/nxp/nxpwifi/11n.c +++ b/drivers/net/wireless/nxp/nxpwifi/11n.c @@ -451,7 +451,7 @@ void nxpwifi_11n_delete_tx_ba_stream_tbl_entry(struct nxpwifi_private *priv, struct nxpwifi_tx_ba_stream_tbl *tbl) { - if (!tbl || nxpwifi_is_tx_ba_stream_ptr_valid(priv, tbl)) + if (!tbl || !nxpwifi_is_tx_ba_stream_ptr_valid(priv, tbl)) return; nxpwifi_dbg(priv->adapter, INFO, From 5e99bdb94720331e2fd38c10c5b1afa1ce640835 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Wed, 26 Aug 2026 00:17:10 +0100 Subject: [PATCH 9/9] wifi: nxpwifi: do not delete Rx reorder entries under RCU The RCU guard is declared in the body of the per-TID loop, so it is still held across the teardown pass. nxpwifi_del_rx_reorder_entry() flushes the Rx workqueue and deletes the reorder timer synchronously, both of which sleep, so a station deauthenticating from the AP splats under CONFIG_DEBUG_ATOMIC_SLEEP. Scope the guard to the collection walk. The teardown does not need RCU: it serialises on priv->rx_reorder_tbl_lock[] and frees with kfree_rcu(). Fixes: 73b01e57ed3e ("wifi: nxp: add nxpwifi driver for IW61x") Assisted-by: Claude:claude-opus-5 Signed-off-by: David Carlier Signed-off-by: Jeff Chen --- drivers/net/wireless/nxp/nxpwifi/11n_rxreorder.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/nxp/nxpwifi/11n_rxreorder.c b/drivers/net/wireless/nxp/nxpwifi/11n_rxreorder.c index 65b628411543..87cf2ec85991 100644 --- a/drivers/net/wireless/nxp/nxpwifi/11n_rxreorder.c +++ b/drivers/net/wireless/nxp/nxpwifi/11n_rxreorder.c @@ -205,11 +205,12 @@ void nxpwifi_11n_del_rx_reorder_tbl_by_ta(struct nxpwifi_private *priv, u8 *ta) return; for (i = 0; i < MAX_NUM_TID; i++) { - guard(rcu)(); - list_for_each_entry_rcu(tbl, &priv->rx_reorder_tbl_ptr[i], list) { - if (!memcmp(tbl->ta, ta, ETH_ALEN)) { - INIT_LIST_HEAD(&tbl->tmp_list); - list_add_tail(&tbl->tmp_list, &to_delete); + scoped_guard(rcu) { + list_for_each_entry_rcu(tbl, &priv->rx_reorder_tbl_ptr[i], list) { + if (!memcmp(tbl->ta, ta, ETH_ALEN)) { + INIT_LIST_HEAD(&tbl->tmp_list); + list_add_tail(&tbl->tmp_list, &to_delete); + } } }