aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Yingqiang Ma <yma.cool@gmail.com>2010-04-13 03:12:07 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-04-20 11:50:51 -0400
commit03ceedea972a82d343fa5c2528b3952fa9e615d5 (patch)
tree7b46f62e4fd82e969bc1cea1999249d25234e330
parente8958330190c57c0d32bee88b64a12de2f58059f (diff)
ath9k: Group Key fix for VAPs
When I set up multiple VAPs with ath9k, I encountered an issue that the traffic may be lost after a while. The detailed phenomenon is 1. After a while the clients connected to one of these VAPs will get into a state that no broadcast/multicast packets can be transfered successfully while the unicast packets can be transfered normally. 2. Minutes latter the unitcast packets transfer will fail as well, because the ARP entry is expired and it can't be freshed due to the broadcast trouble. It's caused by the group key overwritten and someone discussed this issue in ath9k-devel maillist before, but haven't work out a fix yet. I referred the method in madwifi, and made a patch for ath9k. The method is to set the high bit of the sender(AP)'s address, and associated that mac and the group key. It requires the hardware supports multicast frame key search. It seems true for AR9160. Not sure whether it's the correct way to fix this issue. But it seems to work in my test. The patch is attached, feel free to revise it. Signed-off-by: Daniel Yingqiang ma <yma.cool@gmail.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c28
-rw-r--r--include/net/mac80211.h1
-rw-r--r--net/mac80211/key.c1
3 files changed, 27 insertions, 3 deletions
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 1f4ea74bf4ca..40136cf63fa4 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -751,6 +751,7 @@ static int ath_key_config(struct ath_common *common,
751 struct ath_hw *ah = common->ah; 751 struct ath_hw *ah = common->ah;
752 struct ath9k_keyval hk; 752 struct ath9k_keyval hk;
753 const u8 *mac = NULL; 753 const u8 *mac = NULL;
754 u8 gmac[ETH_ALEN];
754 int ret = 0; 755 int ret = 0;
755 int idx; 756 int idx;
756 757
@@ -774,9 +775,30 @@ static int ath_key_config(struct ath_common *common,
774 memcpy(hk.kv_val, key->key, key->keylen); 775 memcpy(hk.kv_val, key->key, key->keylen);
775 776
776 if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) { 777 if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
777 /* For now, use the default keys for broadcast keys. This may 778
778 * need to change with virtual interfaces. */ 779 if (key->ap_addr) {
779 idx = key->keyidx; 780 /*
781 * Group keys on hardware that supports multicast frame
782 * key search use a mac that is the sender's address with
783 * the high bit set instead of the app-specified address.
784 */
785 memcpy(gmac, key->ap_addr, ETH_ALEN);
786 gmac[0] |= 0x80;
787 mac = gmac;
788
789 if (key->alg == ALG_TKIP)
790 idx = ath_reserve_key_cache_slot_tkip(common);
791 else
792 idx = ath_reserve_key_cache_slot(common);
793 if (idx < 0)
794 mac = NULL; /* no free key cache entries */
795 }
796
797 if (!mac) {
798 /* For now, use the default keys for broadcast keys. This may
799 * need to change with virtual interfaces. */
800 idx = key->keyidx;
801 }
780 } else if (key->keyidx) { 802 } else if (key->keyidx) {
781 if (WARN_ON(!sta)) 803 if (WARN_ON(!sta))
782 return -EOPNOTSUPP; 804 return -EOPNOTSUPP;
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index c49e6adcd8fa..63e9d37e3e71 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -793,6 +793,7 @@ struct ieee80211_key_conf {
793 u8 iv_len; 793 u8 iv_len;
794 u8 hw_key_idx; 794 u8 hw_key_idx;
795 u8 flags; 795 u8 flags;
796 u8 *ap_addr;
796 s8 keyidx; 797 s8 keyidx;
797 u8 keylen; 798 u8 keylen;
798 u8 key[0]; 799 u8 key[0];
diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index 8160d9c5372e..75705bd41956 100644
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -139,6 +139,7 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
139 struct ieee80211_sub_if_data, 139 struct ieee80211_sub_if_data,
140 u.ap); 140 u.ap);
141 141
142 key->conf.ap_addr = sdata->dev->dev_addr;
142 ret = drv_set_key(key->local, SET_KEY, sdata, sta, &key->conf); 143 ret = drv_set_key(key->local, SET_KEY, sdata, sta, &key->conf);
143 144
144 if (!ret) { 145 if (!ret) {