mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-03 18:12:25 -04:00
ath11k: fix resource leak in ath11k_mac_sta_state
Handled the error case with proper resource cleanup and moved the handling into a separate function from ath11k_mac_sta_state. Signed-off-by: Karthikeyan Periyasamy <periyasa@codeaurora.org> Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
This commit is contained in:
committed by
Kalle Valo
parent
86d4def890
commit
5e97128759
@@ -2682,6 +2682,87 @@ static void ath11k_mac_dec_num_stations(struct ath11k_vif *arvif,
|
||||
ar->num_stations--;
|
||||
}
|
||||
|
||||
static int ath11k_mac_station_add(struct ath11k *ar,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta)
|
||||
{
|
||||
struct ath11k_base *ab = ar->ab;
|
||||
struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
|
||||
struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
|
||||
struct peer_create_params peer_param;
|
||||
int ret;
|
||||
|
||||
lockdep_assert_held(&ar->conf_mutex);
|
||||
|
||||
ret = ath11k_mac_inc_num_stations(arvif, sta);
|
||||
if (ret) {
|
||||
ath11k_warn(ab, "refusing to associate station: too many connected already (%d)\n",
|
||||
ar->max_num_stations);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
arsta->rx_stats = kzalloc(sizeof(*arsta->rx_stats), GFP_KERNEL);
|
||||
if (!arsta->rx_stats) {
|
||||
ret = -ENOMEM;
|
||||
goto dec_num_station;
|
||||
}
|
||||
|
||||
peer_param.vdev_id = arvif->vdev_id;
|
||||
peer_param.peer_addr = sta->addr;
|
||||
peer_param.peer_type = WMI_PEER_TYPE_DEFAULT;
|
||||
|
||||
ret = ath11k_peer_create(ar, arvif, sta, &peer_param);
|
||||
if (ret) {
|
||||
ath11k_warn(ab, "Failed to add peer: %pM for VDEV: %d\n",
|
||||
sta->addr, arvif->vdev_id);
|
||||
goto free_rx_stats;
|
||||
}
|
||||
|
||||
ath11k_dbg(ab, ATH11K_DBG_MAC, "Added peer: %pM for VDEV: %d\n",
|
||||
sta->addr, arvif->vdev_id);
|
||||
|
||||
if (ath11k_debug_is_extd_tx_stats_enabled(ar)) {
|
||||
arsta->tx_stats = kzalloc(sizeof(*arsta->tx_stats), GFP_KERNEL);
|
||||
if (!arsta->tx_stats) {
|
||||
ret = -ENOMEM;
|
||||
goto free_peer;
|
||||
}
|
||||
}
|
||||
|
||||
if (ieee80211_vif_is_mesh(vif)) {
|
||||
ret = ath11k_wmi_set_peer_param(ar, sta->addr,
|
||||
arvif->vdev_id,
|
||||
WMI_PEER_USE_4ADDR, 1);
|
||||
if (ret) {
|
||||
ath11k_warn(ab, "failed to STA %pM 4addr capability: %d\n",
|
||||
sta->addr, ret);
|
||||
goto free_tx_stats;
|
||||
}
|
||||
}
|
||||
|
||||
ret = ath11k_dp_peer_setup(ar, arvif->vdev_id, sta->addr);
|
||||
if (ret) {
|
||||
ath11k_warn(ab, "failed to setup dp for peer %pM on vdev %i (%d)\n",
|
||||
sta->addr, arvif->vdev_id, ret);
|
||||
goto free_tx_stats;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
free_tx_stats:
|
||||
kfree(arsta->tx_stats);
|
||||
arsta->tx_stats = NULL;
|
||||
free_peer:
|
||||
ath11k_peer_delete(ar, arvif->vdev_id, sta->addr);
|
||||
free_rx_stats:
|
||||
kfree(arsta->rx_stats);
|
||||
arsta->rx_stats = NULL;
|
||||
dec_num_station:
|
||||
ath11k_mac_dec_num_stations(arvif, sta);
|
||||
exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath11k_mac_op_sta_state(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta,
|
||||
@@ -2691,7 +2772,6 @@ static int ath11k_mac_op_sta_state(struct ieee80211_hw *hw,
|
||||
struct ath11k *ar = hw->priv;
|
||||
struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
|
||||
struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
|
||||
struct peer_create_params peer_param;
|
||||
int ret = 0;
|
||||
|
||||
/* cancel must be done outside the mutex to avoid deadlock */
|
||||
@@ -2707,60 +2787,10 @@ static int ath11k_mac_op_sta_state(struct ieee80211_hw *hw,
|
||||
arsta->arvif = arvif;
|
||||
INIT_WORK(&arsta->update_wk, ath11k_sta_rc_update_wk);
|
||||
|
||||
ret = ath11k_mac_inc_num_stations(arvif, sta);
|
||||
if (ret) {
|
||||
ath11k_warn(ar->ab, "refusing to associate station: too many connected already (%d)\n",
|
||||
ar->max_num_stations);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
arsta->rx_stats = kzalloc(sizeof(*arsta->rx_stats), GFP_KERNEL);
|
||||
if (!arsta->rx_stats) {
|
||||
ret = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
peer_param.vdev_id = arvif->vdev_id;
|
||||
peer_param.peer_addr = sta->addr;
|
||||
peer_param.peer_type = WMI_PEER_TYPE_DEFAULT;
|
||||
ret = ath11k_peer_create(ar, arvif, sta, &peer_param);
|
||||
if (ret) {
|
||||
ath11k_warn(ar->ab, "Failed to add peer: %pM for VDEV: %d\n",
|
||||
ret = ath11k_mac_station_add(ar, vif, sta);
|
||||
if (ret)
|
||||
ath11k_warn(ar->ab, "Failed to add station: %pM for VDEV: %d\n",
|
||||
sta->addr, arvif->vdev_id);
|
||||
ath11k_mac_dec_num_stations(arvif, sta);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ath11k_info(ar->ab, "Added peer: %pM for VDEV: %d\n",
|
||||
sta->addr, arvif->vdev_id);
|
||||
|
||||
if (ath11k_debug_is_extd_tx_stats_enabled(ar)) {
|
||||
arsta->tx_stats = kzalloc(sizeof(*arsta->tx_stats),
|
||||
GFP_KERNEL);
|
||||
if (!arsta->tx_stats) {
|
||||
ret = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
if (ieee80211_vif_is_mesh(vif)) {
|
||||
ret = ath11k_wmi_set_peer_param(ar, sta->addr,
|
||||
arvif->vdev_id,
|
||||
WMI_PEER_USE_4ADDR, 1);
|
||||
if (ret) {
|
||||
ath11k_warn(ar->ab, "failed to STA %pM 4addr capability: %d\n",
|
||||
sta->addr, ret);
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
ret = ath11k_dp_peer_setup(ar, arvif->vdev_id, sta->addr);
|
||||
if (ret) {
|
||||
ath11k_warn(ar->ab, "failed to setup dp for peer %pM on vdev %i (%d)\n",
|
||||
sta->addr, arvif->vdev_id, ret);
|
||||
ath11k_peer_delete(ar, arvif->vdev_id, sta->addr);
|
||||
ath11k_mac_dec_num_stations(arvif, sta);
|
||||
}
|
||||
} else if ((old_state == IEEE80211_STA_NONE &&
|
||||
new_state == IEEE80211_STA_NOTEXIST)) {
|
||||
ath11k_dp_peer_cleanup(ar, arvif->vdev_id, sta->addr);
|
||||
@@ -2770,9 +2800,8 @@ static int ath11k_mac_op_sta_state(struct ieee80211_hw *hw,
|
||||
ath11k_warn(ar->ab, "Failed to delete peer: %pM for VDEV: %d\n",
|
||||
sta->addr, arvif->vdev_id);
|
||||
else
|
||||
ath11k_info(ar->ab,
|
||||
"Removed peer: %pM for VDEV: %d\n",
|
||||
sta->addr, arvif->vdev_id);
|
||||
ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "Removed peer: %pM for VDEV: %d\n",
|
||||
sta->addr, arvif->vdev_id);
|
||||
|
||||
ath11k_mac_dec_num_stations(arvif, sta);
|
||||
|
||||
@@ -2809,7 +2838,6 @@ static int ath11k_mac_op_sta_state(struct ieee80211_hw *hw,
|
||||
sta->addr);
|
||||
}
|
||||
|
||||
exit:
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user