ath9k: assign keycache slots to unencrypted stations
authorFelix Fietkau <nbd@openwrt.org>
Sun, 17 Apr 2011 21:28:10 +0000 (23:28 +0200)
committerJohn W. Linville <linville@tuxdriver.com>
Tue, 19 Apr 2011 19:38:06 +0000 (15:38 -0400)
Frame filtering relies on having a valid destination index (keycache slot),
to keep track of the destination. Assigning a keycache slot (configured
to unencrypted, with no key data attached) improves powersave handling in
AP mode with no encryption.
The dummy keycache entry for a station is cleared, when a real key gets
added.

Signed-off-by: Felix Fietkau <nbd@openwrt.org>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/ath/key.c

index a2ddabf0ca2f2a3199f7402d2d53f6cf326c0ad3..a6b538802251ae4108fd1ac4027bcf66c5b2da70 100644 (file)
@@ -256,6 +256,8 @@ struct ath_node {
 #endif
        struct ath_atx_tid tid[WME_NUM_TID];
        struct ath_atx_ac ac[WME_NUM_AC];
+       int ps_key;
+
        u16 maxampdu;
        u8 mpdudensity;
 
index 01df5876fda1d5e34e5a3bfcb0d43ee25f8cdce7..e7d6d98ed1ccb5e214df503100cd80959fe3566e 100644 (file)
@@ -1732,18 +1732,37 @@ static int ath9k_sta_add(struct ieee80211_hw *hw,
                         struct ieee80211_sta *sta)
 {
        struct ath_softc *sc = hw->priv;
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       struct ath_node *an = (struct ath_node *) sta->drv_priv;
+       struct ieee80211_key_conf ps_key = { };
 
        ath_node_attach(sc, sta);
+       an->ps_key = ath_key_config(common, vif, sta, &ps_key);
 
        return 0;
 }
 
+static void ath9k_del_ps_key(struct ath_softc *sc,
+                            struct ieee80211_vif *vif,
+                            struct ieee80211_sta *sta)
+{
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       struct ath_node *an = (struct ath_node *) sta->drv_priv;
+       struct ieee80211_key_conf ps_key = { .hw_key_idx = an->ps_key };
+
+       if (!an->ps_key)
+           return;
+
+       ath_key_delete(common, &ps_key);
+}
+
 static int ath9k_sta_remove(struct ieee80211_hw *hw,
                            struct ieee80211_vif *vif,
                            struct ieee80211_sta *sta)
 {
        struct ath_softc *sc = hw->priv;
 
+       ath9k_del_ps_key(sc, vif, sta);
        ath_node_detach(sc, sta);
 
        return 0;
@@ -1844,6 +1863,9 @@ static int ath9k_set_key(struct ieee80211_hw *hw,
 
        switch (cmd) {
        case SET_KEY:
+               if (sta)
+                       ath9k_del_ps_key(sc, vif, sta);
+
                ret = ath_key_config(common, vif, sta, key);
                if (ret >= 0) {
                        key->hw_key_idx = ret;
index 48ff8c22ba1ffebba8859a3c078f53a700ea733c..65d46c6ebced44245d2071dca7b400f71b4fa70e 100644 (file)
@@ -1526,7 +1526,7 @@ static void setup_frame_info(struct ieee80211_hw *hw, struct sk_buff *skb,
        struct ieee80211_key_conf *hw_key = tx_info->control.hw_key;
        struct ieee80211_hdr *hdr;
        struct ath_frame_info *fi = get_frame_info(skb);
-       struct ath_node *an;
+       struct ath_node *an = NULL;
        struct ath_atx_tid *tid;
        enum ath9k_key_type keytype;
        u16 seqno = 0;
@@ -1534,11 +1534,13 @@ static void setup_frame_info(struct ieee80211_hw *hw, struct sk_buff *skb,
 
        keytype = ath9k_cmn_get_hw_crypto_keytype(skb);
 
+       if (sta)
+               an = (struct ath_node *) sta->drv_priv;
+
        hdr = (struct ieee80211_hdr *)skb->data;
-       if (sta && ieee80211_is_data_qos(hdr->frame_control) &&
+       if (an && ieee80211_is_data_qos(hdr->frame_control) &&
                conf_is_ht(&hw->conf) && (sc->sc_flags & SC_OP_TXAGGR)) {
 
-               an = (struct ath_node *) sta->drv_priv;
                tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK;
 
                /*
@@ -1554,6 +1556,8 @@ static void setup_frame_info(struct ieee80211_hw *hw, struct sk_buff *skb,
        memset(fi, 0, sizeof(*fi));
        if (hw_key)
                fi->keyix = hw_key->hw_key_idx;
+       else if (an && ieee80211_is_data(hdr->frame_control) && an->ps_key > 0)
+               fi->keyix = an->ps_key;
        else
                fi->keyix = ATH9K_TXKEYIX_INVALID;
        fi->keytype = keytype;
index 0d4f39cbdcabfef96fe9ccc6ca5dcfe3fa6d591a..a61ef3d6d89c7ee50da52b9602071dd88bb9eb5b 100644 (file)
@@ -483,6 +483,9 @@ int ath_key_config(struct ath_common *common,
        memset(&hk, 0, sizeof(hk));
 
        switch (key->cipher) {
+       case 0:
+               hk.kv_type = ATH_CIPHER_CLR;
+               break;
        case WLAN_CIPHER_SUITE_WEP40:
        case WLAN_CIPHER_SUITE_WEP104:
                hk.kv_type = ATH_CIPHER_WEP;
@@ -498,7 +501,8 @@ int ath_key_config(struct ath_common *common,
        }
 
        hk.kv_len = key->keylen;
-       memcpy(hk.kv_val, key->key, key->keylen);
+       if (key->keylen)
+               memcpy(hk.kv_val, key->key, key->keylen);
 
        if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
                switch (vif->type) {