Commit 4bbf4414 authored by Rajkumar Manoharan's avatar Rajkumar Manoharan Committed by John W. Linville

ath9k: Handle multiple keys while setting tx filters

The keycache index is used to abort transmission for given station
when it goes to sleep state. But the commit "ath9k_hw: Abort transmission
for sleeping station" is not handling multi-key station. Fix that.

Cc: Felix Fietkau <nbd@openwrt.org>
Signed-off-by: default avatarRajkumar Manoharan <rmanohar@qti.qualcomm.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 09869495
...@@ -274,6 +274,7 @@ struct ath_node { ...@@ -274,6 +274,7 @@ struct ath_node {
#ifdef CONFIG_ATH9K_STATION_STATISTICS #ifdef CONFIG_ATH9K_STATION_STATISTICS
struct ath_rx_rate_stats rx_rate_stats; struct ath_rx_rate_stats rx_rate_stats;
#endif #endif
u8 key_idx[4];
}; };
struct ath_tx_control { struct ath_tx_control {
......
...@@ -421,6 +421,7 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta, ...@@ -421,6 +421,7 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta,
an->sc = sc; an->sc = sc;
an->sta = sta; an->sta = sta;
an->vif = vif; an->vif = vif;
memset(&an->key_idx, 0, sizeof(an->key_idx));
ath_tx_node_init(sc, an); ath_tx_node_init(sc, an);
} }
...@@ -1461,8 +1462,10 @@ static int ath9k_sta_add(struct ieee80211_hw *hw, ...@@ -1461,8 +1462,10 @@ static int ath9k_sta_add(struct ieee80211_hw *hw,
return 0; return 0;
key = ath_key_config(common, vif, sta, &ps_key); key = ath_key_config(common, vif, sta, &ps_key);
if (key > 0) if (key > 0) {
an->ps_key = key; an->ps_key = key;
an->key_idx[0] = key;
}
return 0; return 0;
} }
...@@ -1480,6 +1483,7 @@ static void ath9k_del_ps_key(struct ath_softc *sc, ...@@ -1480,6 +1483,7 @@ static void ath9k_del_ps_key(struct ath_softc *sc,
ath_key_delete(common, &ps_key); ath_key_delete(common, &ps_key);
an->ps_key = 0; an->ps_key = 0;
an->key_idx[0] = 0;
} }
static int ath9k_sta_remove(struct ieee80211_hw *hw, static int ath9k_sta_remove(struct ieee80211_hw *hw,
...@@ -1494,6 +1498,19 @@ static int ath9k_sta_remove(struct ieee80211_hw *hw, ...@@ -1494,6 +1498,19 @@ static int ath9k_sta_remove(struct ieee80211_hw *hw,
return 0; return 0;
} }
static void ath9k_sta_set_tx_filter(struct ath_hw *ah,
struct ath_node *an,
bool set)
{
int i;
for (i = 0; i < ARRAY_SIZE(an->key_idx); i++) {
if (!an->key_idx[i])
continue;
ath9k_hw_set_tx_filter(ah, an->key_idx[i], set);
}
}
static void ath9k_sta_notify(struct ieee80211_hw *hw, static void ath9k_sta_notify(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
enum sta_notify_cmd cmd, enum sta_notify_cmd cmd,
...@@ -1506,12 +1523,10 @@ static void ath9k_sta_notify(struct ieee80211_hw *hw, ...@@ -1506,12 +1523,10 @@ static void ath9k_sta_notify(struct ieee80211_hw *hw,
case STA_NOTIFY_SLEEP: case STA_NOTIFY_SLEEP:
an->sleeping = true; an->sleeping = true;
ath_tx_aggr_sleep(sta, sc, an); ath_tx_aggr_sleep(sta, sc, an);
if (an->ps_key > 0) ath9k_sta_set_tx_filter(sc->sc_ah, an, true);
ath9k_hw_set_tx_filter(sc->sc_ah, an->ps_key, true);
break; break;
case STA_NOTIFY_AWAKE: case STA_NOTIFY_AWAKE:
if (an->ps_key > 0) ath9k_sta_set_tx_filter(sc->sc_ah, an, false);
ath9k_hw_set_tx_filter(sc->sc_ah, an->ps_key, false);
an->sleeping = false; an->sleeping = false;
ath_tx_aggr_wakeup(sc, an); ath_tx_aggr_wakeup(sc, an);
break; break;
...@@ -1567,7 +1582,8 @@ static int ath9k_set_key(struct ieee80211_hw *hw, ...@@ -1567,7 +1582,8 @@ static int ath9k_set_key(struct ieee80211_hw *hw,
{ {
struct ath_softc *sc = hw->priv; struct ath_softc *sc = hw->priv;
struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_common *common = ath9k_hw_common(sc->sc_ah);
int ret = 0; struct ath_node *an = NULL;
int ret = 0, i;
if (ath9k_modparam_nohwcrypt) if (ath9k_modparam_nohwcrypt)
return -ENOSPC; return -ENOSPC;
...@@ -1589,16 +1605,17 @@ static int ath9k_set_key(struct ieee80211_hw *hw, ...@@ -1589,16 +1605,17 @@ static int ath9k_set_key(struct ieee80211_hw *hw,
mutex_lock(&sc->mutex); mutex_lock(&sc->mutex);
ath9k_ps_wakeup(sc); ath9k_ps_wakeup(sc);
ath_dbg(common, CONFIG, "Set HW Key\n"); ath_dbg(common, CONFIG, "Set HW Key %d\n", cmd);
if (sta)
an = (struct ath_node *)sta->drv_priv;
switch (cmd) { switch (cmd) {
case SET_KEY: case SET_KEY:
if (sta) if (sta)
ath9k_del_ps_key(sc, vif, sta); ath9k_del_ps_key(sc, vif, sta);
key->hw_key_idx = 0;
ret = ath_key_config(common, vif, sta, key); ret = ath_key_config(common, vif, sta, key);
if (sta && (ret > 0))
((struct ath_node *)sta->drv_priv)->ps_key = ret;
if (ret >= 0) { if (ret >= 0) {
key->hw_key_idx = ret; key->hw_key_idx = ret;
/* push IV and Michael MIC generation to stack */ /* push IV and Michael MIC generation to stack */
...@@ -1610,11 +1627,27 @@ static int ath9k_set_key(struct ieee80211_hw *hw, ...@@ -1610,11 +1627,27 @@ static int ath9k_set_key(struct ieee80211_hw *hw,
key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX; key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX;
ret = 0; ret = 0;
} }
if (an && key->hw_key_idx) {
for (i = 0; i < ARRAY_SIZE(an->key_idx); i++) {
if (an->key_idx[i])
continue;
an->key_idx[i] = key->hw_key_idx;
break;
}
WARN_ON(i == ARRAY_SIZE(an->key_idx));
}
break; break;
case DISABLE_KEY: case DISABLE_KEY:
ath_key_delete(common, key); ath_key_delete(common, key);
if (sta) if (an) {
((struct ath_node *)sta->drv_priv)->ps_key = 0; for (i = 0; i < ARRAY_SIZE(an->key_idx); i++) {
if (an->key_idx[i] != key->hw_key_idx)
continue;
an->key_idx[i] = 0;
break;
}
}
key->hw_key_idx = 0;
break; break;
default: default:
ret = -EINVAL; ret = -EINVAL;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment