@@ -141,20 +141,21 @@ static void ieee80211_key_enable_hw_acce
ret = drv_set_key(key->local, SET_KEY, &sdata->vif, sta, &key->conf);
- if (!ret) {
- spin_lock_bh(&todo_lock);
+ spin_lock_bh(&todo_lock);
+ if (!ret)
key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE;
- spin_unlock_bh(&todo_lock);
- }
+ else if (ret == -EOPNOTSUPP)
+ key->flags |= KEY_FLAG_HWACCEL_NOT_SUPPORTED;
+ spin_unlock_bh(&todo_lock);
- if (ret && ret != -ENOSPC && ret != -EOPNOTSUPP)
- printk(KERN_ERR "mac80211-%s: failed to set key "
- "(%d, %pM) to hardware (%d)\n",
- wiphy_name(key->local->hw.wiphy),
- key->conf.keyidx, sta ? sta->addr : bcast_addr, ret);
+ WARN(ret && ret != -ENOSPC && ret != -EOPNOTSUPP,
+ "mac80211-%s: failed to set key (%d, %pM) to hardware (%d)\n",
+ wiphy_name(key->local->hw.wiphy), key->conf.keyidx,
+ sta ? sta->addr : bcast_addr, ret);
}
-static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
+static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key,
+ bool upload_another)
{
struct ieee80211_sub_if_data *sdata;
struct ieee80211_sta *sta;
@@ -184,14 +185,30 @@ static void ieee80211_key_disable_hw_acc
ret = drv_set_key(key->local, DISABLE_KEY, &sdata->vif,
sta, &key->conf);
- if (ret)
- printk(KERN_ERR "mac80211-%s: failed to remove key "
- "(%d, %pM) from hardware (%d)\n",
- wiphy_name(key->local->hw.wiphy),
- key->conf.keyidx, sta ? sta->addr : bcast_addr, ret);
+ WARN(ret,
+ "mac80211-%s: failed to remove key (%d, %pM) from hardware (%d)\n",
+ wiphy_name(key->local->hw.wiphy), key->conf.keyidx,
+ sta ? sta->addr : bcast_addr, ret);
spin_lock_bh(&todo_lock);
key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
+
+ list_for_each_entry(key, &sdata->key_list, list) {
+ if (key->flags & KEY_FLAG_HWACCEL_NOT_SUPPORTED)
+ continue;
+ if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)
+ continue;
+ if (key->flags & KEY_FLAG_TODO_DELETE)
+ continue;
+ if (key->flags & KEY_FLAG_TODO_HWACCEL_ADD)
+ continue;
+ if (key->flags & KEY_FLAG_TODO_HWACCEL_REMOVE)
+ continue;
+ spin_unlock_bh(&todo_lock);
+ ieee80211_key_enable_hw_accel(key);
+ spin_lock_bh(&todo_lock);
+ }
+
spin_unlock_bh(&todo_lock);
}
@@ -527,7 +544,7 @@ static void __ieee80211_key_destroy(stru
if (!key)
return;
- ieee80211_key_disable_hw_accel(key);
+ ieee80211_key_disable_hw_accel(key, true);
if (key->conf.alg == ALG_CCMP)
ieee80211_aes_key_free(key->u.ccmp.tfm);
@@ -583,7 +600,7 @@ static void __ieee80211_key_todo(void)
work_done = true;
}
if (todoflags & KEY_FLAG_TODO_HWACCEL_REMOVE) {
- ieee80211_key_disable_hw_accel(key);
+ ieee80211_key_disable_hw_accel(key, false);
work_done = true;
}
if (todoflags & KEY_FLAG_TODO_DELETE) {
@@ -48,6 +48,8 @@ struct sta_info;
* @KEY_FLAG_TODO_ADD_DEBUGFS: Key needs to be added to debugfs.
* @KEY_FLAG_TODO_DEFMGMTKEY: Key is default management key and debugfs needs
* to be updated.
+ * @KEY_FLAG_HWACCEL_NOT_SUPPORTED: hardware acceleration not supported for
+ * this key type (tried and driver returned -EOPNOTSUPP)
*/
enum ieee80211_internal_key_flags {
KEY_FLAG_UPLOADED_TO_HARDWARE = BIT(0),
@@ -57,6 +59,7 @@ enum ieee80211_internal_key_flags {
KEY_FLAG_TODO_DEFKEY = BIT(4),
KEY_FLAG_TODO_ADD_DEBUGFS = BIT(5),
KEY_FLAG_TODO_DEFMGMTKEY = BIT(6),
+ KEY_FLAG_HWACCEL_NOT_SUPPORTED = BIT(7),
};
struct tkip_ctx {
When we remove a key from hwaccel, that may mean that there's a new free item in the hwaccel, and we could fill it with another station's key. By keeping track of which keys the driver said it could not support (-EOPNOTSUPP) and which it had no space for (-ENOSPC) we can try uploading a key that was previously rejected due to no space after another key is removed. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> --- RFT because I really have no idea how to test this properly. Maybe with a hacked driver that claims to support only a single key in hwaccel? net/mac80211/key.c | 51 ++++++++++++++++++++++++++++++++++----------------- net/mac80211/key.h | 3 +++ 2 files changed, 37 insertions(+), 17 deletions(-) -- To unsubscribe from this list: send the line "unsubscribe linux-wireless" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html