aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/ath9k/main.c
diff options
context:
space:
mode:
authorRajkumar Manoharan <rmanohar@qti.qualcomm.com>2014-05-22 03:05:49 -0400
committerJohn W. Linville <linville@tuxdriver.com>2014-05-22 14:04:38 -0400
commit4bbf4414d2494aea8d72eefd47a4b0b272175865 (patch)
treedc929ce09076134958ad66e213322c3360699f9b /drivers/net/wireless/ath/ath9k/main.c
parent09869495616af7e5098aabb6f3eefdf885235699 (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.c55
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
1485static int ath9k_sta_remove(struct ieee80211_hw *hw, 1489static 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
1501static 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
1497static void ath9k_sta_notify(struct ieee80211_hw *hw, 1514static 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;