ath10k: use workqueue to set WEP TX key
Recent WMI/HTC changes made it possible for WMI commands to sleep (if there's not enough HTC TX credits to submit a command). TX path is in an atomic context so calling WMI commands in it is wrong. This simply moves WEP key index update to a worker and fixes the 'scheduling while atomic' bug. This still leaves multiple WEP key handling laggy, i.e. some frames may be TXed with an old/different key (although recipient should still be able to RX them). kvalo: changed the title Signed-off-by: Michal Kazior <michal.kazior@tieto.com> Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
This commit is contained in:
parent
d544943afa
commit
cc4827b97b
|
@ -215,8 +215,10 @@ struct ath10k_vif {
|
||||||
struct ath10k *ar;
|
struct ath10k *ar;
|
||||||
struct ieee80211_vif *vif;
|
struct ieee80211_vif *vif;
|
||||||
|
|
||||||
|
struct work_struct wep_key_work;
|
||||||
struct ieee80211_key_conf *wep_keys[WMI_MAX_KEY_INDEX + 1];
|
struct ieee80211_key_conf *wep_keys[WMI_MAX_KEY_INDEX + 1];
|
||||||
u8 def_wep_key_index;
|
u8 def_wep_key_idx;
|
||||||
|
u8 def_wep_key_newidx;
|
||||||
|
|
||||||
u16 tx_seq_no;
|
u16 tx_seq_no;
|
||||||
|
|
||||||
|
|
|
@ -1239,7 +1239,7 @@ static void ath10k_bss_disassoc(struct ieee80211_hw *hw,
|
||||||
/* FIXME: why don't we print error if wmi call fails? */
|
/* FIXME: why don't we print error if wmi call fails? */
|
||||||
ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id);
|
ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id);
|
||||||
|
|
||||||
arvif->def_wep_key_index = 0;
|
arvif->def_wep_key_idx = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif,
|
static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif,
|
||||||
|
@ -1467,6 +1467,30 @@ static void ath10k_tx_h_qos_workaround(struct ieee80211_hw *hw,
|
||||||
skb_pull(skb, IEEE80211_QOS_CTL_LEN);
|
skb_pull(skb, IEEE80211_QOS_CTL_LEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ath10k_tx_wep_key_work(struct work_struct *work)
|
||||||
|
{
|
||||||
|
struct ath10k_vif *arvif = container_of(work, struct ath10k_vif,
|
||||||
|
wep_key_work);
|
||||||
|
int ret, keyidx = arvif->def_wep_key_newidx;
|
||||||
|
|
||||||
|
if (arvif->def_wep_key_idx == keyidx)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d set keyidx %d\n",
|
||||||
|
arvif->vdev_id, keyidx);
|
||||||
|
|
||||||
|
ret = ath10k_wmi_vdev_set_param(arvif->ar,
|
||||||
|
arvif->vdev_id,
|
||||||
|
arvif->ar->wmi.vdev_param->def_keyid,
|
||||||
|
keyidx);
|
||||||
|
if (ret) {
|
||||||
|
ath10k_warn("could not update wep keyidx (%d)\n", ret);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
arvif->def_wep_key_idx = keyidx;
|
||||||
|
}
|
||||||
|
|
||||||
static void ath10k_tx_h_update_wep_key(struct sk_buff *skb)
|
static void ath10k_tx_h_update_wep_key(struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||||
|
@ -1475,8 +1499,6 @@ static void ath10k_tx_h_update_wep_key(struct sk_buff *skb)
|
||||||
struct ath10k *ar = arvif->ar;
|
struct ath10k *ar = arvif->ar;
|
||||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||||
struct ieee80211_key_conf *key = info->control.hw_key;
|
struct ieee80211_key_conf *key = info->control.hw_key;
|
||||||
u32 vdev_param;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (!ieee80211_has_protected(hdr->frame_control))
|
if (!ieee80211_has_protected(hdr->frame_control))
|
||||||
return;
|
return;
|
||||||
|
@ -1488,21 +1510,14 @@ static void ath10k_tx_h_update_wep_key(struct sk_buff *skb)
|
||||||
key->cipher != WLAN_CIPHER_SUITE_WEP104)
|
key->cipher != WLAN_CIPHER_SUITE_WEP104)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (key->keyidx == arvif->def_wep_key_index)
|
if (key->keyidx == arvif->def_wep_key_idx)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d keyidx %d\n",
|
/* FIXME: Most likely a few frames will be TXed with an old key. Simply
|
||||||
arvif->vdev_id, key->keyidx);
|
* queueing frames until key index is updated is not an option because
|
||||||
|
* sk_buff may need more processing to be done, e.g. offchannel */
|
||||||
vdev_param = ar->wmi.vdev_param->def_keyid;
|
arvif->def_wep_key_newidx = key->keyidx;
|
||||||
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
|
ieee80211_queue_work(ar->hw, &arvif->wep_key_work);
|
||||||
key->keyidx);
|
|
||||||
if (ret) {
|
|
||||||
ath10k_warn("could not update wep keyidx (%d)\n", ret);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
arvif->def_wep_key_index = key->keyidx;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ath10k_tx_h_add_p2p_noa_ie(struct ath10k *ar, struct sk_buff *skb)
|
static void ath10k_tx_h_add_p2p_noa_ie(struct ath10k *ar, struct sk_buff *skb)
|
||||||
|
@ -2023,6 +2038,8 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
|
||||||
arvif->ar = ar;
|
arvif->ar = ar;
|
||||||
arvif->vif = vif;
|
arvif->vif = vif;
|
||||||
|
|
||||||
|
INIT_WORK(&arvif->wep_key_work, ath10k_tx_wep_key_work);
|
||||||
|
|
||||||
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;
|
||||||
|
@ -2078,7 +2095,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
|
||||||
|
|
||||||
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_index);
|
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);
|
||||||
|
|
||||||
|
@ -2147,6 +2164,8 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
|
||||||
|
|
||||||
mutex_lock(&ar->conf_mutex);
|
mutex_lock(&ar->conf_mutex);
|
||||||
|
|
||||||
|
cancel_work_sync(&arvif->wep_key_work);
|
||||||
|
|
||||||
spin_lock_bh(&ar->data_lock);
|
spin_lock_bh(&ar->data_lock);
|
||||||
if (arvif->beacon) {
|
if (arvif->beacon) {
|
||||||
dev_kfree_skb_any(arvif->beacon);
|
dev_kfree_skb_any(arvif->beacon);
|
||||||
|
|
Loading…
Reference in New Issue