[PATCH AUTOSEL 6.19-6.12] wifi: rtw88: Use devm_kmemdup() in rtw_set_supported_band()

Sasha Levin
2026-02-14T21:26:55Z

From: Bitterblue Smith <rtl8821cerfe2@gmail.com>

[ Upstream commit 2ba12401cc1f2d970fa2e7d5b15abde3f5abd40d ]

Simplify the code by using device managed memory allocations.

This also fixes a memory leak in rtw_register_hw(). The supported bands
were not freed in the error path.

Copied from commit 145df52a8671 ("wifi: rtw89: Convert
rtw89_core_set_supported_band to use devm_*").

Signed-off-by: Bitterblue Smith <rtl8821cerfe2@gmail.com>
Acked-by: Ping-Ke Shih <pkshih@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
Link: https://patch.msgid.link/1aa7fdef-2d5b-4a31-a4e9-fac8257ed30d@gmail.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---

LLM Generated explanations, may be completely bogus:

## Analysis

### Commit Message Analysis

The commit message is explicit about fixing a bug: **"This also fixes a
memory leak in rtw_register_hw(). The supported bands were not freed in
the error path."**

The primary change converts `kmemdup()` to `devm_kmemdup()` (device-
managed memory), which means the memory will be automatically freed when
the device is removed. This simultaneously:
1. Simplifies the code (removes manual `rtw_unset_supported_band()`
function)
2. **Fixes a real memory leak** on the error path of `rtw_register_hw()`

### Code Change Analysis

Let me trace the bug:

1. `rtw_set_supported_band()` allocates memory with `kmemdup()` for 2GHz
and 5GHz band structures
2. `rtw_register_hw()` calls `rtw_set_supported_band()` early in its
flow
3. If `rtw_register_hw()` fails later (e.g., at `rtw_regd_hint()` →
`goto led_deinit`), the error path does NOT call
`rtw_unset_supported_band()` to free those allocations
4. The old `rtw_unset_supported_band()` was only called in
`rtw_unregister_hw()`, which is the normal teardown path — not the
error path

Let me verify this by examining the error path structure in the diff.
The `rtw_register_hw()` function has error paths (`goto led_deinit`)
that return without freeing the band allocations. This is a genuine
memory leak.

### The Fix

The fix converts to `devm_kmemdup()`, which ties the allocation lifetime
to the device. This means:
- On error paths: memory is freed when the device is cleaned up (no
leak)
- On normal unregister: memory is freed automatically (no need for
`rtw_unset_supported_band()`)

The `rtw_unset_supported_band()` function is removed entirely since it's
no longer needed, and the call to it in `rtw_unregister_hw()` is also
removed.

### Stable Criteria Assessment

1. **Fixes a real bug**: Yes — memory leak on error path in
`rtw_register_hw()`. If probe fails repeatedly (e.g., USB WiFi dongle
being plugged/unplugged), this leaks memory each time.
2. **Obviously correct**: Yes — the pattern of converting from `kmemdup`
to `devm_kmemdup` is well-established and was already done in the
sister driver rtw89 (commit 145df52a8671).
3. **Small and contained**: Yes — changes a single file, ~20 lines of
actual logic change, rest is removal of now-unnecessary code.
4. **No new features**: Correct — this is purely a bug fix with code
simplification.
5. **Tested**: Has `Acked-by` from the Realtek maintainer (Ping-Ke
Shih).

### Risk Assessment

**Low risk**:
- `devm_kmemdup()` is a standard, well-tested kernel API
- The same pattern was already applied to rtw89 (the newer sibling
driver)
- The change is straightforward — swap allocation function, remove
manual free function
- The rtw88 driver is widely used (RTL8822BE, RTL8822CE, RTL8821CE are
common WiFi chips)

**One potential concern**: The devm-managed memory will be freed when
the device is destroyed, while the old code freed it in
`rtw_unregister_hw()`. However, since `ieee80211_unregister_hw()` is
called before the device is destroyed, and that function removes the
wiphy, the bands won't be accessed after the devm memory is freed. This
ordering is safe.

### User Impact

The rtw88 driver covers commonly used Realtek WiFi chips found in many
laptops. Memory leaks during driver initialization failures could
accumulate, especially for USB-based variants where plug/unplug cycles
are common. This is a real-world issue.

### Dependency Check

This commit appears self-contained. `devm_kmemdup()` has been available
in the kernel for a long time. The function signature changes are all
internal to `main.c`. No other patches are needed.

### Conclusion

This commit fixes a genuine memory leak in a widely-used WiFi driver.
The fix is small, well-understood, uses standard kernel APIs, and has
been reviewed/acked by the subsystem maintainer. The pattern was already
proven in the rtw89 driver. It meets all stable kernel criteria.

**YES**

drivers/net/wireless/realtek/rtw88/main.c | 19 ++++++-------------
1 file changed, 6 insertions(+), 13 deletions(-)

diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c
index 361ce0d40956d..2004d714530a3 100644
--- a/drivers/net/wireless/realtek/rtw88/main.c
+++ b/drivers/net/wireless/realtek/rtw88/main.c
@@ -1661,11 +1661,13 @@ static u16 rtw_get_max_scan_ie_len(struct rtw_dev *rtwdev)
static void rtw_set_supported_band(struct ieee80211_hw *hw,
const struct rtw_chip_info *chip)
{
- struct rtw_dev *rtwdev = hw->priv;
struct ieee80211_supported_band *sband;
+ struct rtw_dev *rtwdev = hw->priv;
+ struct device *dev = rtwdev->dev;

if (chip->band & RTW_BAND_2G) {
- sband = kmemdup(&rtw_band_2ghz, sizeof(*sband), GFP_KERNEL);
+ sband = devm_kmemdup(dev, &rtw_band_2ghz, sizeof(*sband),
+ GFP_KERNEL);
if (!sband)
goto err_out;
if (chip->ht_supported)
@@ -1674,7 +1676,8 @@ static void rtw_set_supported_band(struct ieee80211_hw *hw,
}

if (chip->band & RTW_BAND_5G) {
- sband = kmemdup(&rtw_band_5ghz, sizeof(*sband), GFP_KERNEL);
+ sband = devm_kmemdup(dev, &rtw_band_5ghz, sizeof(*sband),
+ GFP_KERNEL);
if (!sband)
goto err_out;
if (chip->ht_supported)
@@ -1690,13 +1693,6 @@ static void rtw_set_supported_band(struct ieee80211_hw *hw,
rtw_err(rtwdev, "failed to set supported band\n");
}

-static void rtw_unset_supported_band(struct ieee80211_hw *hw,
- const struct rtw_chip_info *chip)
-{
- kfree(hw->wiphy->bands[NL80211_BAND_2GHZ]);
- kfree(hw->wiphy->bands[NL80211_BAND_5GHZ]);
-}
-
static void rtw_vif_smps_iter(void *data, u8 *mac,
struct ieee80211_vif *vif)
{
@@ -2320,10 +2316,7 @@ EXPORT_SYMBOL(rtw_register_hw);

void rtw_unregister_hw(struct rtw_dev *rtwdev, struct ieee80211_hw *hw)
{
- const struct rtw_chip_info *chip = rtwdev->chip;
-
ieee80211_unregister_hw(hw);
- rtw_unset_supported_band(hw, chip);
rtw_debugfs_deinit(rtwdev);
rtw_led_deinit(rtwdev);
}
--
2.51.0