rtw88: some fixes of hw_scan
Ping-Ke Shih
maintainercover rtw88: some fixes of hw_scan
Since patch 2/3 and 3/3 is based on the first patch sent by Muhammad
https://lore.kernel.org/linux-wireless/YcWK1jxnd3vGdmCq@debian-BULLSEYE-live-builder-AMD64/
I put them together in this patchset, so we don't miss it.
The second patch is to enter idle mode by driver after hw_scan, and then it can save more power. Third patch is to fix memory overrun and leak that will lead kernel crash.
Muhammad Usama Anjum (1):
rtw88: check for validity before using a pointer
Po-Hao Huang (2):
rtw88: fix idle mode flow for hw scan
rtw88: fix memory overrun and memory leak during hw_scan
drivers/net/wireless/realtek/rtw88/fw.c | 40 ++++++++++++++----- drivers/net/wireless/realtek/rtw88/mac80211.c | 5 ++- drivers/net/wireless/realtek/rtw88/main.c | 16 +++++++- drivers/net/wireless/realtek/rtw88/main.h | 4 +- 4 files changed, 53 insertions(+), 12 deletions(-)
Signature · 1 line
2.25.1
Ping-Ke Shih
maintainerPATCH 1/3 rtw88: check for validity before using a pointer
From: Muhammad Usama Anjum <[email protected]>
ieee80211_probereq_get() can return NULL. Pointer skb should be checked for validty before use. If it is not valid, list of skbs needs to be freed.
--- drivers/net/wireless/realtek/rtw88/fw.c | 8 ++++++++ 1 file changed, 8 insertions(+)
drivers/net/wireless/realtek/rtw88/fw.c +8 -0
@@ -1866,11 +1866,19 @@ static int rtw_hw_scan_update_probe_req(struct rtw_dev *rtwdev, req->ssids[i].ssid, req->ssids[i].ssid_len, req->ie_len); +if (!skb) + goto out;rtw_append_probe_req_ie (rtwdev, skb, &list, rtwvif);kfree_skb (skb); }return _rtw_hw_scan_update_probe_req (rtwdev, num, &list); + +out: + skb_queue_walk(&list, skb) +kfree_skb (skb); + +return -ENOMEM ; } static int rtw_add_chan_info(struct rtw_dev *rtwdev, struct rtw_chan_info *info,
Signature · 1 line
2.25.1
Re: [PATCH 1/3] rtw88: check for validity before using a pointer
Quoted 9 lines · Ping-Ke Shih
From: Muhammad Usama Anjum <[email protected]>
ieee80211_probereq_get()can return NULL. Pointer skb should be checked for validty before use. If it is not valid, list of skbs needs to be freed.Fixes 10d162b2ed39 ("rtw88: 8822c: add ieee80211_ops::hw_scan")Signed-off-by Muhammad Usama Anjum <[email protected]>Signed-off-by Ping-Ke Shih <[email protected]>
3 patches applied to wireless-next.git, thanks.
a12f809968db rtw88: check for validity before using a pointer c17f27167b4c rtw88: fix idle mode flow for hw scan d95984b5580d rtw88: fix memory overrun and memory leak during hw_scan
Signature · 3 lines
https://patchwork.kernel.org/project/linux-wireless/patch/[email protected]/ https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
Ping-Ke Shih
maintainerPATCH 2/3 rtw88: fix idle mode flow for hw scan
In reply to Ping-Ke ShihFrom: Po-Hao Huang <[email protected]>
Upon hw scan completion, idle mode is not re-entered. This might increase power consumption under no link mode. Fix this by adding the re-enter flow. We need another work for this since enter_ips waits for c2h_work to finish, which might lead to deadlock if caller is in the same work.
--- drivers/net/wireless/realtek/rtw88/fw.c | 2 +- drivers/net/wireless/realtek/rtw88/mac80211.c | 5 ++++- drivers/net/wireless/realtek/rtw88/main.c | 16 +++++++++++++++- drivers/net/wireless/realtek/rtw88/main.h | 4 +++- 4 files changed, 23 insertions(+), 4 deletions(-)
drivers/net/wireless/realtek/rtw88/fw.c +1 -1
@@ -2030,7 +2030,7 @@ void rtw_hw_scan_complete(struct rtw_dev *rtwdev, struct ieee80211_vif *vif, rtwdev->hal.rcr |=BIT_CBSSID_BCN ;rtw_write32 (rtwdev,REG_RCR , rtwdev->hal.rcr); -rtw_core_scan_complete (rtwdev, vif); +rtw_core_scan_complete (rtwdev, vif, true);ieee80211_wake_queues (rtwdev->hw);ieee80211_scan_completed (rtwdev->hw, &info);
drivers/net/wireless/realtek/rtw88/mac80211.c +4 -1
@@ -72,6 +72,9 @@ static int rtw_ops_config(struct ieee80211_hw *hw, u32 changed)struct rtw_dev *rtwdev = hw->priv;int ret =0 ; +/* let previous ips work finish to ensure we don't leave ips twice */ +cancel_work_sync (&rtwdev->ips_work); +mutex_lock (&rtwdev->mutex);rtw_leave_lps_deep (rtwdev);
@@ -614,7 +617,7 @@ static void rtw_ops_sw_scan_complete(struct ieee80211_hw *hw,struct rtw_dev *rtwdev = hw->priv;mutex_lock (&rtwdev->mutex); -rtw_core_scan_complete (rtwdev, vif); +rtw_core_scan_complete (rtwdev, vif, false);mutex_unlock (&rtwdev->mutex); }
drivers/net/wireless/realtek/rtw88/main.c +15 -1
@@ -272,6 +272,15 @@ static void rtw_c2h_work(struct work_struct *work) } } +static void rtw_ips_work (struct work_struct *work) +{ + struct rtw_dev *rtwdev = container_of(work, struct rtw_dev, ips_work); + +mutex_lock (&rtwdev->mutex); +rtw_enter_ips (rtwdev); +mutex_unlock (&rtwdev->mutex); +} +static u8 rtw_acquire_macid (struct rtw_dev *rtwdev) {unsigned long mac_id;
@@ -1339,7 +1348,8 @@ void rtw_core_scan_start(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif,set_bit (RTW_FLAG_SCANNING , rtwdev->flags); } -void rtw_core_scan_complete (struct rtw_dev *rtwdev,struct ieee80211_vif *vif) +void rtw_core_scan_complete (struct rtw_dev *rtwdev,struct ieee80211_vif *vif, +bool hw_scan) {struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv;u32 config =0 ;
@@ -1354,6 +1364,9 @@ void rtw_core_scan_complete(struct rtw_dev *rtwdev, struct ieee80211_vif *vif)rtw_vif_port_config (rtwdev, rtwvif, config);rtw_coex_scan_notify (rtwdev,COEX_SCAN_FINISH ); + +if (rtwvif->net_type ==RTW_NET_NO_LINK && hw_scan) +ieee80211_queue_work (rtwdev->hw, &rtwdev->ips_work); }int rtw_core_start (struct rtw_dev *rtwdev)
@@ -1919,6 +1932,7 @@ int rtw_core_init(struct rtw_dev *rtwdev)INIT_DELAYED_WORK (&coex->wl_ccklock_work, rtw_coex_wl_ccklock_work);INIT_WORK (&rtwdev->tx_work, rtw_tx_work);INIT_WORK (&rtwdev->c2h_work, rtw_c2h_work); +INIT_WORK (&rtwdev->ips_work, rtw_ips_work);INIT_WORK (&rtwdev->fw_recovery_work, rtw_fw_recovery_work);INIT_WORK (&rtwdev->ba_work, rtw_txq_ba_work);skb_queue_head_init (&rtwdev->c2h_queue);
drivers/net/wireless/realtek/rtw88/main.h +3 -1
@@ -1960,6 +1960,7 @@ struct rtw_dev {/* c2h cmd queue & handler work */ struct sk_buff_head c2h_queue;struct work_struct c2h_work; +struct work_struct ips_work;struct work_struct fw_recovery_work;/* used to protect txqs list */
@@ -2101,7 +2102,8 @@ void rtw_tx_report_purge_timer(struct timer_list *t);void rtw_update_sta_info (struct rtw_dev *rtwdev,struct rtw_sta_info *si);void rtw_core_scan_start (struct rtw_dev *rtwdev,struct rtw_vif *rtwvif,const u8 *mac_addr,bool hw_scan); -void rtw_core_scan_complete (struct rtw_dev *rtwdev,struct ieee80211_vif *vif); +void rtw_core_scan_complete (struct rtw_dev *rtwdev,struct ieee80211_vif *vif, +bool hw_scan);int rtw_core_start (struct rtw_dev *rtwdev);void rtw_core_stop (struct rtw_dev *rtwdev);int rtw_chip_info_setup (struct rtw_dev *rtwdev);
Signature · 1 line
2.25.1
Ping-Ke Shih
maintainerPATCH 3/3 rtw88: fix memory overrun and memory leak during hw_scan
In reply to Ping-Ke ShihFrom: Po-Hao Huang <[email protected]>
Previously we allocated less memory than actual required, overwrite to the buffer causes the mm module to complaint and raise access violation faults. Along with potential memory leaks when returned early. Fix these by passing the correct size and proper deinit flow.
--- drivers/net/wireless/realtek/rtw88/fw.c | 34 +++++++++++++++++-------- 1 file changed, 24 insertions(+), 10 deletions(-)
drivers/net/wireless/realtek/rtw88/fw.c +24 -10
@@ -1784,9 +1784,9 @@ void rtw_fw_scan_notify(struct rtw_dev *rtwdev, bool start)rtw_fw_send_h2c_command (rtwdev, h2c_pkt); } -static void rtw_append_probe_req_ie (struct rtw_dev *rtwdev,struct sk_buff *skb, -struct sk_buff_head *list, -struct rtw_vif *rtwvif) +static int rtw_append_probe_req_ie (struct rtw_dev *rtwdev,struct sk_buff *skb, +struct sk_buff_head *list,u8 *bands, +struct rtw_vif *rtwvif) {struct ieee80211_scan_ies *ies = rtwvif->scan_ies;struct rtw_chip_info *chip = rtwdev->chip;
@@ -1797,19 +1797,24 @@ static void rtw_append_probe_req_ie(struct rtw_dev *rtwdev, struct sk_buff *skb,if (!(BIT (idx) & chip->band))continue ; new =skb_copy (skb,GFP_KERNEL ); +if (!new) +return -ENOMEM ;skb_put_data (new, ies->ies[idx], ies->len[idx]);skb_put_data (new, ies->common_ies, ies->common_ie_len);skb_queue_tail (list, new); + (*bands)++; } + +return 0 ; } -static int _rtw_hw_scan_update_probe_req (struct rtw_dev *rtwdev,u8 num_ssids, +static int _rtw_hw_scan_update_probe_req (struct rtw_dev *rtwdev,u8 num_probes,struct sk_buff_head *probe_req_list) {struct rtw_chip_info *chip = rtwdev->chip;struct sk_buff *skb, *tmp;u8 page_offset =1 , *buf, page_size = chip->page_size; -u8 pages = page_offset + num_ssids *RTW_PROBE_PG_CNT ; +u8 pages = page_offset + num_probes *RTW_PROBE_PG_CNT ;u16 pg_addr = rtwdev->fifo.rsvd_h2c_info_addr, loc;u16 buf_offset = page_size * page_offset;u8 tx_desc_sz = chip->tx_pkt_desc_sz;
@@ -1848,6 +1853,8 @@ static int _rtw_hw_scan_update_probe_req(struct rtw_dev *rtwdev, u8 num_ssids, rtwdev->scan_info.probe_pg_size = page_offset; out:kfree (buf); + skb_queue_walk(probe_req_list, skb) +kfree_skb (skb);return ret; }
@@ -1858,7 +1865,8 @@ static int rtw_hw_scan_update_probe_req(struct rtw_dev *rtwdev,struct cfg80211_scan_request *req = rtwvif->scan_req;struct sk_buff_head list;struct sk_buff *skb; -u8 num = req->n_ssids, i; +u8 num = req->n_ssids, i, bands =0 ; +int ret;skb_queue_head_init (&list);for (i =0 ; i < num; i++) {
@@ -1866,19 +1874,25 @@ static int rtw_hw_scan_update_probe_req(struct rtw_dev *rtwdev, req->ssids[i].ssid, req->ssids[i].ssid_len, req->ie_len); -if (!skb) +if (!skb) { + ret = -ENOMEM ; goto out; -rtw_append_probe_req_ie (rtwdev, skb, &list, rtwvif); + } + ret =rtw_append_probe_req_ie (rtwdev, skb, &list, &bands, + rtwvif); +if (ret) + goto out; +kfree_skb (skb); } -return _rtw_hw_scan_update_probe_req (rtwdev, num, &list); +return _rtw_hw_scan_update_probe_req (rtwdev, num * bands, &list); out: skb_queue_walk(&list, skb)kfree_skb (skb); -return -ENOMEM ; +return ret; } static int rtw_add_chan_info(struct rtw_dev *rtwdev, struct rtw_chan_info *info,
Signature · 1 line
2.25.1