ath10k: fix add_interface failure handling
If something failed along add_interface() setup it was possible to leak a vdev id, vdev and peer. This could end up with leaked FW state or FW crash (assuming add_interface() failure wasn't a result of a crash). kvalo: rebased, whitespace fixes Signed-off-by: Michal Kazior <michal.kazior@tieto.com> Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
This commit is contained in:
parent
cc4827b97b
commit
9dad14ae28
|
@ -2043,18 +2043,17 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
|
||||||
if ((vif->type == NL80211_IFTYPE_MONITOR) && ar->monitor_present) {
|
if ((vif->type == NL80211_IFTYPE_MONITOR) && ar->monitor_present) {
|
||||||
ath10k_warn("Only one monitor interface allowed\n");
|
ath10k_warn("Only one monitor interface allowed\n");
|
||||||
ret = -EBUSY;
|
ret = -EBUSY;
|
||||||
goto exit;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
bit = ffs(ar->free_vdev_map);
|
bit = ffs(ar->free_vdev_map);
|
||||||
if (bit == 0) {
|
if (bit == 0) {
|
||||||
ret = -EBUSY;
|
ret = -EBUSY;
|
||||||
goto exit;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
arvif->vdev_id = bit - 1;
|
arvif->vdev_id = bit - 1;
|
||||||
arvif->vdev_subtype = WMI_VDEV_SUBTYPE_NONE;
|
arvif->vdev_subtype = WMI_VDEV_SUBTYPE_NONE;
|
||||||
ar->free_vdev_map &= ~(1 << arvif->vdev_id);
|
|
||||||
|
|
||||||
if (ar->p2p)
|
if (ar->p2p)
|
||||||
arvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_DEVICE;
|
arvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_DEVICE;
|
||||||
|
@ -2090,27 +2089,33 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
|
||||||
arvif->vdev_subtype, vif->addr);
|
arvif->vdev_subtype, vif->addr);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
ath10k_warn("WMI vdev create failed: ret %d\n", ret);
|
ath10k_warn("WMI vdev create failed: ret %d\n", ret);
|
||||||
goto exit;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ar->free_vdev_map &= ~BIT(arvif->vdev_id);
|
||||||
|
|
||||||
vdev_param = ar->wmi.vdev_param->def_keyid;
|
vdev_param = ar->wmi.vdev_param->def_keyid;
|
||||||
ret = ath10k_wmi_vdev_set_param(ar, 0, vdev_param,
|
ret = ath10k_wmi_vdev_set_param(ar, 0, vdev_param,
|
||||||
arvif->def_wep_key_idx);
|
arvif->def_wep_key_idx);
|
||||||
if (ret)
|
if (ret) {
|
||||||
ath10k_warn("Failed to set default keyid: %d\n", ret);
|
ath10k_warn("Failed to set default keyid: %d\n", ret);
|
||||||
|
goto err_vdev_delete;
|
||||||
|
}
|
||||||
|
|
||||||
vdev_param = ar->wmi.vdev_param->tx_encap_type;
|
vdev_param = ar->wmi.vdev_param->tx_encap_type;
|
||||||
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
|
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
|
||||||
ATH10K_HW_TXRX_NATIVE_WIFI);
|
ATH10K_HW_TXRX_NATIVE_WIFI);
|
||||||
/* 10.X firmware does not support this VDEV parameter. Do not warn */
|
/* 10.X firmware does not support this VDEV parameter. Do not warn */
|
||||||
if (ret && ret != -EOPNOTSUPP)
|
if (ret && ret != -EOPNOTSUPP) {
|
||||||
ath10k_warn("Failed to set TX encap: %d\n", ret);
|
ath10k_warn("Failed to set TX encap: %d\n", ret);
|
||||||
|
goto err_vdev_delete;
|
||||||
|
}
|
||||||
|
|
||||||
if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
|
if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
|
||||||
ret = ath10k_peer_create(ar, arvif->vdev_id, vif->addr);
|
ret = ath10k_peer_create(ar, arvif->vdev_id, vif->addr);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
ath10k_warn("Failed to create peer for AP: %d\n", ret);
|
ath10k_warn("Failed to create peer for AP: %d\n", ret);
|
||||||
goto exit;
|
goto err_vdev_delete;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2119,39 +2124,61 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
|
||||||
value = WMI_STA_PS_RX_WAKE_POLICY_WAKE;
|
value = WMI_STA_PS_RX_WAKE_POLICY_WAKE;
|
||||||
ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id,
|
ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id,
|
||||||
param, value);
|
param, value);
|
||||||
if (ret)
|
if (ret) {
|
||||||
ath10k_warn("Failed to set RX wake policy: %d\n", ret);
|
ath10k_warn("Failed to set RX wake policy: %d\n", ret);
|
||||||
|
goto err_peer_delete;
|
||||||
|
}
|
||||||
|
|
||||||
param = WMI_STA_PS_PARAM_TX_WAKE_THRESHOLD;
|
param = WMI_STA_PS_PARAM_TX_WAKE_THRESHOLD;
|
||||||
value = WMI_STA_PS_TX_WAKE_THRESHOLD_ALWAYS;
|
value = WMI_STA_PS_TX_WAKE_THRESHOLD_ALWAYS;
|
||||||
ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id,
|
ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id,
|
||||||
param, value);
|
param, value);
|
||||||
if (ret)
|
if (ret) {
|
||||||
ath10k_warn("Failed to set TX wake thresh: %d\n", ret);
|
ath10k_warn("Failed to set TX wake thresh: %d\n", ret);
|
||||||
|
goto err_peer_delete;
|
||||||
|
}
|
||||||
|
|
||||||
param = WMI_STA_PS_PARAM_PSPOLL_COUNT;
|
param = WMI_STA_PS_PARAM_PSPOLL_COUNT;
|
||||||
value = WMI_STA_PS_PSPOLL_COUNT_NO_MAX;
|
value = WMI_STA_PS_PSPOLL_COUNT_NO_MAX;
|
||||||
ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id,
|
ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id,
|
||||||
param, value);
|
param, value);
|
||||||
if (ret)
|
if (ret) {
|
||||||
ath10k_warn("Failed to set PSPOLL count: %d\n", ret);
|
ath10k_warn("Failed to set PSPOLL count: %d\n", ret);
|
||||||
|
goto err_peer_delete;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = ath10k_mac_set_rts(arvif, ar->hw->wiphy->rts_threshold);
|
ret = ath10k_mac_set_rts(arvif, ar->hw->wiphy->rts_threshold);
|
||||||
if (ret)
|
if (ret) {
|
||||||
ath10k_warn("failed to set rts threshold for vdev %d (%d)\n",
|
ath10k_warn("failed to set rts threshold for vdev %d (%d)\n",
|
||||||
arvif->vdev_id, ret);
|
arvif->vdev_id, ret);
|
||||||
|
goto err_peer_delete;
|
||||||
|
}
|
||||||
|
|
||||||
ret = ath10k_mac_set_frag(arvif, ar->hw->wiphy->frag_threshold);
|
ret = ath10k_mac_set_frag(arvif, ar->hw->wiphy->frag_threshold);
|
||||||
if (ret)
|
if (ret) {
|
||||||
ath10k_warn("failed to set frag threshold for vdev %d (%d)\n",
|
ath10k_warn("failed to set frag threshold for vdev %d (%d)\n",
|
||||||
arvif->vdev_id, ret);
|
arvif->vdev_id, ret);
|
||||||
|
goto err_peer_delete;
|
||||||
|
}
|
||||||
|
|
||||||
if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR)
|
if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR)
|
||||||
ar->monitor_present = true;
|
ar->monitor_present = true;
|
||||||
|
|
||||||
exit:
|
|
||||||
mutex_unlock(&ar->conf_mutex);
|
mutex_unlock(&ar->conf_mutex);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err_peer_delete:
|
||||||
|
if (arvif->vdev_type == WMI_VDEV_TYPE_AP)
|
||||||
|
ath10k_wmi_peer_delete(ar, arvif->vdev_id, vif->addr);
|
||||||
|
|
||||||
|
err_vdev_delete:
|
||||||
|
ath10k_wmi_vdev_delete(ar, arvif->vdev_id);
|
||||||
|
ar->free_vdev_map &= ~BIT(arvif->vdev_id);
|
||||||
|
|
||||||
|
err:
|
||||||
|
mutex_unlock(&ar->conf_mutex);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue