diff options
author | Rajkumar Manoharan <rmanohar@qti.qualcomm.com> | 2014-05-22 03:05:49 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2014-05-22 14:04:38 -0400 |
commit | 4bbf4414d2494aea8d72eefd47a4b0b272175865 (patch) | |
tree | dc929ce09076134958ad66e213322c3360699f9b /drivers/net/wireless/ath/ath9k/main.c | |
parent | 09869495616af7e5098aabb6f3eefdf885235699 (diff) |
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: Rajkumar Manoharan <rmanohar@qti.qualcomm.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/main.c')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/main.c | 55 |
1 files changed, 44 insertions, 11 deletions
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 47d442a288cf..6965ceac7bc6 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c | |||
@@ -421,6 +421,7 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta, | |||
421 | an->sc = sc; | 421 | an->sc = sc; |
422 | an->sta = sta; | 422 | an->sta = sta; |
423 | an->vif = vif; | 423 | an->vif = vif; |
424 | memset(&an->key_idx, 0, sizeof(an->key_idx)); | ||
424 | 425 | ||
425 | ath_tx_node_init(sc, an); | 426 | ath_tx_node_init(sc, an); |
426 | } | 427 | } |
@@ -1461,8 +1462,10 @@ static int ath9k_sta_add(struct ieee80211_hw *hw, | |||
1461 | return 0; | 1462 | return 0; |
1462 | 1463 | ||
1463 | key = ath_key_config(common, vif, sta, &ps_key); | 1464 | key = ath_key_config(common, vif, sta, &ps_key); |
1464 | if (key > 0) | 1465 | if (key > 0) { |
1465 | an->ps_key = key; | 1466 | an->ps_key = key; |
1467 | an->key_idx[0] = key; | ||
1468 | } | ||
1466 | 1469 | ||
1467 | return 0; | 1470 | return 0; |
1468 | } | 1471 | } |
@@ -1480,6 +1483,7 @@ static void ath9k_del_ps_key(struct ath_softc *sc, | |||
1480 | 1483 | ||
1481 | ath_key_delete(common, &ps_key); | 1484 | ath_key_delete(common, &ps_key); |
1482 | an->ps_key = 0; | 1485 | an->ps_key = 0; |
1486 | an->key_idx[0] = 0; | ||
1483 | } | 1487 | } |
1484 | 1488 | ||
1485 | static int ath9k_sta_remove(struct ieee80211_hw *hw, | 1489 | static int ath9k_sta_remove(struct ieee80211_hw *hw, |
@@ -1494,6 +1498,19 @@ static int ath9k_sta_remove(struct ieee80211_hw *hw, | |||
1494 | return 0; | 1498 | return 0; |
1495 | } | 1499 | } |
1496 | 1500 | ||
1501 | static void ath9k_sta_set_tx_filter(struct ath_hw *ah, | ||
1502 | struct ath_node *an, | ||
1503 | bool set) | ||
1504 | { | ||
1505 | int i; | ||
1506 | |||
1507 | for (i = 0; i < ARRAY_SIZE(an->key_idx); i++) { | ||
1508 | if (!an->key_idx[i]) | ||
1509 | continue; | ||
1510 | ath9k_hw_set_tx_filter(ah, an->key_idx[i], set); | ||
1511 | } | ||
1512 | } | ||
1513 | |||
1497 | static void ath9k_sta_notify(struct ieee80211_hw *hw, | 1514 | static void ath9k_sta_notify(struct ieee80211_hw *hw, |
1498 | struct ieee80211_vif *vif, | 1515 | struct ieee80211_vif *vif, |
1499 | enum sta_notify_cmd cmd, | 1516 | enum sta_notify_cmd cmd, |
@@ -1506,12 +1523,10 @@ static void ath9k_sta_notify(struct ieee80211_hw *hw, | |||
1506 | case STA_NOTIFY_SLEEP: | 1523 | case STA_NOTIFY_SLEEP: |
1507 | an->sleeping = true; | 1524 | an->sleeping = true; |
1508 | ath_tx_aggr_sleep(sta, sc, an); | 1525 | ath_tx_aggr_sleep(sta, sc, an); |
1509 | if (an->ps_key > 0) | 1526 | ath9k_sta_set_tx_filter(sc->sc_ah, an, true); |
1510 | ath9k_hw_set_tx_filter(sc->sc_ah, an->ps_key, true); | ||
1511 | break; | 1527 | break; |
1512 | case STA_NOTIFY_AWAKE: | 1528 | case STA_NOTIFY_AWAKE: |
1513 | if (an->ps_key > 0) | 1529 | ath9k_sta_set_tx_filter(sc->sc_ah, an, false); |
1514 | ath9k_hw_set_tx_filter(sc->sc_ah, an->ps_key, false); | ||
1515 | an->sleeping = false; | 1530 | an->sleeping = false; |
1516 | ath_tx_aggr_wakeup(sc, an); | 1531 | ath_tx_aggr_wakeup(sc, an); |
1517 | break; | 1532 | break; |
@@ -1567,7 +1582,8 @@ static int ath9k_set_key(struct ieee80211_hw *hw, | |||
1567 | { | 1582 | { |
1568 | struct ath_softc *sc = hw->priv; | 1583 | struct ath_softc *sc = hw->priv; |
1569 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 1584 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
1570 | int ret = 0; | 1585 | struct ath_node *an = NULL; |
1586 | int ret = 0, i; | ||
1571 | 1587 | ||
1572 | if (ath9k_modparam_nohwcrypt) | 1588 | if (ath9k_modparam_nohwcrypt) |
1573 | return -ENOSPC; | 1589 | return -ENOSPC; |
@@ -1589,16 +1605,17 @@ static int ath9k_set_key(struct ieee80211_hw *hw, | |||
1589 | 1605 | ||
1590 | mutex_lock(&sc->mutex); | 1606 | mutex_lock(&sc->mutex); |
1591 | ath9k_ps_wakeup(sc); | 1607 | ath9k_ps_wakeup(sc); |
1592 | ath_dbg(common, CONFIG, "Set HW Key\n"); | 1608 | ath_dbg(common, CONFIG, "Set HW Key %d\n", cmd); |
1609 | if (sta) | ||
1610 | an = (struct ath_node *)sta->drv_priv; | ||
1593 | 1611 | ||
1594 | switch (cmd) { | 1612 | switch (cmd) { |
1595 | case SET_KEY: | 1613 | case SET_KEY: |
1596 | if (sta) | 1614 | if (sta) |
1597 | ath9k_del_ps_key(sc, vif, sta); | 1615 | ath9k_del_ps_key(sc, vif, sta); |
1598 | 1616 | ||
1617 | key->hw_key_idx = 0; | ||
1599 | ret = ath_key_config(common, vif, sta, key); | 1618 | ret = ath_key_config(common, vif, sta, key); |
1600 | if (sta && (ret > 0)) | ||
1601 | ((struct ath_node *)sta->drv_priv)->ps_key = ret; | ||
1602 | if (ret >= 0) { | 1619 | if (ret >= 0) { |
1603 | key->hw_key_idx = ret; | 1620 | key->hw_key_idx = ret; |
1604 | /* push IV and Michael MIC generation to stack */ | 1621 | /* push IV and Michael MIC generation to stack */ |
@@ -1610,11 +1627,27 @@ static int ath9k_set_key(struct ieee80211_hw *hw, | |||
1610 | key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX; | 1627 | key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX; |
1611 | ret = 0; | 1628 | ret = 0; |
1612 | } | 1629 | } |
1630 | if (an && key->hw_key_idx) { | ||
1631 | for (i = 0; i < ARRAY_SIZE(an->key_idx); i++) { | ||
1632 | if (an->key_idx[i]) | ||
1633 | continue; | ||
1634 | an->key_idx[i] = key->hw_key_idx; | ||
1635 | break; | ||
1636 | } | ||
1637 | WARN_ON(i == ARRAY_SIZE(an->key_idx)); | ||
1638 | } | ||
1613 | break; | 1639 | break; |
1614 | case DISABLE_KEY: | 1640 | case DISABLE_KEY: |
1615 | ath_key_delete(common, key); | 1641 | ath_key_delete(common, key); |
1616 | if (sta) | 1642 | if (an) { |
1617 | ((struct ath_node *)sta->drv_priv)->ps_key = 0; | 1643 | for (i = 0; i < ARRAY_SIZE(an->key_idx); i++) { |
1644 | if (an->key_idx[i] != key->hw_key_idx) | ||
1645 | continue; | ||
1646 | an->key_idx[i] = 0; | ||
1647 | break; | ||
1648 | } | ||
1649 | } | ||
1650 | key->hw_key_idx = 0; | ||
1618 | break; | 1651 | break; |
1619 | default: | 1652 | default: |
1620 | ret = -EINVAL; | 1653 | ret = -EINVAL; |