rt2x00: Fix rt2800 key assignment in multi bssid setups
authorHelmut Schaa <helmut.schaa@googlemail.com>
Thu, 3 Mar 2011 18:44:33 +0000 (19:44 +0100)
committerJohn W. Linville <linville@tuxdriver.com>
Fri, 4 Mar 2011 19:06:48 +0000 (14:06 -0500)
When setting up multiple BSSIDs in AP mode on an rt2800pci device we
previously used the STAs AID to select an appropriate key slot. But
since the AID is per VIF we can end up with two STAs having the same AID
and thus using the same key index. This resulted in one STA overwriting
the key information of another STA.

Fix this by simply searching for the next unused entry in the pairwise
key table.

Also bring the key table init in sync with deleting keys by initializing
the key table entries to 0 instead of 1.

Signed-off-by: Helmut Schaa <helmut.schaa@googlemail.com>
Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/rt2x00/rt2800lib.c

index 553d4d0..2ee6ceb 100644 (file)
@@ -1101,27 +1101,44 @@ int rt2800_config_shared_key(struct rt2x00_dev *rt2x00dev,
 }
 EXPORT_SYMBOL_GPL(rt2800_config_shared_key);
 
+static inline int rt2800_find_pairwise_keyslot(struct rt2x00_dev *rt2x00dev)
+{
+       int idx;
+       u32 offset, reg;
+
+       /*
+        * Search for the first free pairwise key entry and return the
+        * corresponding index.
+        *
+        * Make sure the WCID starts _after_ the last possible shared key
+        * entry (>32).
+        *
+        * Since parts of the pairwise key table might be shared with
+        * the beacon frame buffers 6 & 7 we should only write into the
+        * first 222 entries.
+        */
+       for (idx = 33; idx <= 222; idx++) {
+               offset = MAC_WCID_ATTR_ENTRY(idx);
+               rt2800_register_read(rt2x00dev, offset, &reg);
+               if (!reg)
+                       return idx;
+       }
+       return -1;
+}
+
 int rt2800_config_pairwise_key(struct rt2x00_dev *rt2x00dev,
                               struct rt2x00lib_crypto *crypto,
                               struct ieee80211_key_conf *key)
 {
        struct hw_key_entry key_entry;
        u32 offset;
+       int idx;
 
        if (crypto->cmd == SET_KEY) {
-               /*
-                * 1 pairwise key is possible per AID, this means that the AID
-                * equals our hw_key_idx. Make sure the WCID starts _after_ the
-                * last possible shared key entry.
-                *
-                * Since parts of the pairwise key table might be shared with
-                * the beacon frame buffers 6 & 7 we should only write into the
-                * first 222 entries.
-                */
-               if (crypto->aid > (222 - 32))
+               idx = rt2800_find_pairwise_keyslot(rt2x00dev);
+               if (idx < 0)
                        return -ENOSPC;
-
-               key->hw_key_idx = 32 + crypto->aid;
+               key->hw_key_idx = idx;
 
                memcpy(key_entry.key, crypto->key,
                       sizeof(key_entry.key));
@@ -2458,7 +2475,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
                rt2800_register_multiwrite(rt2x00dev, MAC_WCID_ENTRY(i),
                                              wcid, sizeof(wcid));
 
-               rt2800_register_write(rt2x00dev, MAC_WCID_ATTR_ENTRY(i), 1);
+               rt2800_register_write(rt2x00dev, MAC_WCID_ATTR_ENTRY(i), 0);
                rt2800_register_write(rt2x00dev, MAC_IVEIV_ENTRY(i), 0);
        }