Commit 6dfe9a88 authored by Christian Lamparter's avatar Christian Lamparter Committed by John W. Linville

p54: utilize all available key slots for decryption offload

This patch takes care of outstanding TODOs:
/* TODO: some devices have 4 more free slots for rx keys */

Now the driver can utilize all available key slots instead of just 4.
Obviously, this helps most in AP/IBSS(/MESH) mode, when
we have to use more different keys.
Signed-off-by: default avatarChristian Lamparter <chunkeey@web.de>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 492301fb
...@@ -186,6 +186,7 @@ struct p54_common { ...@@ -186,6 +186,7 @@ struct p54_common {
/* cryptographic engine information */ /* cryptographic engine information */
u8 privacy_caps; u8 privacy_caps;
u8 rx_keycache_size; u8 rx_keycache_size;
unsigned long *used_rxkeys;
/* LED management */ /* LED management */
#ifdef CONFIG_MAC80211_LEDS #ifdef CONFIG_MAC80211_LEDS
......
...@@ -249,7 +249,7 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) ...@@ -249,7 +249,7 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
dev->queues = P54_QUEUE_AC_NUM; dev->queues = P54_QUEUE_AC_NUM;
} }
if (!modparam_nohwcrypt) if (!modparam_nohwcrypt) {
printk(KERN_INFO "%s: cryptographic accelerator " printk(KERN_INFO "%s: cryptographic accelerator "
"WEP:%s, TKIP:%s, CCMP:%s\n", "WEP:%s, TKIP:%s, CCMP:%s\n",
wiphy_name(dev->wiphy), wiphy_name(dev->wiphy),
...@@ -259,6 +259,26 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) ...@@ -259,6 +259,26 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
(priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP) ? (priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP) ?
"YES" : "no"); "YES" : "no");
if (priv->rx_keycache_size) {
/*
* NOTE:
*
* The firmware provides at most 255 (0 - 254) slots
* for keys which are then used to offload decryption.
* As a result the 255 entry (aka 0xff) can be used
* safely by the driver to mark keys that didn't fit
* into the full cache. This trick saves us from
* keeping a extra list for uploaded keys.
*/
priv->used_rxkeys = kzalloc(BITS_TO_LONGS(
priv->rx_keycache_size), GFP_KERNEL);
if (!priv->used_rxkeys)
return -ENOMEM;
}
}
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(p54_parse_firmware); EXPORT_SYMBOL_GPL(p54_parse_firmware);
...@@ -2355,61 +2375,84 @@ static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd, ...@@ -2355,61 +2375,84 @@ static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd,
struct p54_common *priv = dev->priv; struct p54_common *priv = dev->priv;
struct sk_buff *skb; struct sk_buff *skb;
struct p54_keycache *rxkey; struct p54_keycache *rxkey;
int slot, ret = 0;
u8 algo = 0; u8 algo = 0;
if (modparam_nohwcrypt) if (modparam_nohwcrypt)
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (cmd == DISABLE_KEY) mutex_lock(&priv->conf_mutex);
algo = 0; if (cmd == SET_KEY) {
else {
switch (key->alg) { switch (key->alg) {
case ALG_TKIP: case ALG_TKIP:
if (!(priv->privacy_caps & (BR_DESC_PRIV_CAP_MICHAEL | if (!(priv->privacy_caps & (BR_DESC_PRIV_CAP_MICHAEL |
BR_DESC_PRIV_CAP_TKIP))) BR_DESC_PRIV_CAP_TKIP))) {
return -EOPNOTSUPP; ret = -EOPNOTSUPP;
goto out_unlock;
}
key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
algo = P54_CRYPTO_TKIPMICHAEL; algo = P54_CRYPTO_TKIPMICHAEL;
break; break;
case ALG_WEP: case ALG_WEP:
if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_WEP)) if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_WEP)) {
return -EOPNOTSUPP; ret = -EOPNOTSUPP;
goto out_unlock;
}
key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
algo = P54_CRYPTO_WEP; algo = P54_CRYPTO_WEP;
break; break;
case ALG_CCMP: case ALG_CCMP:
if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP)) if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP)) {
return -EOPNOTSUPP; ret = -EOPNOTSUPP;
goto out_unlock;
}
key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
algo = P54_CRYPTO_AESCCMP; algo = P54_CRYPTO_AESCCMP;
break; break;
default: default:
return -EOPNOTSUPP; ret = -EOPNOTSUPP;
} goto out_unlock;
} }
slot = bitmap_find_free_region(priv->used_rxkeys,
priv->rx_keycache_size, 0);
if (key->keyidx > priv->rx_keycache_size) { if (slot < 0) {
/* /*
* The device supports the choosen algorithm, but the firmware * The device supports the choosen algorithm, but the
* does not provide enough key slots to store all of them. * firmware does not provide enough key slots to store
* So, incoming frames have to be decoded by the mac80211 stack, * all of them.
* but we can still offload encryption for outgoing frames. * But encryption offload for outgoing frames is always
* possible, so we just pretend that the upload was
* successful and do the decryption in software.
*/ */
return 0; /* mark the key as invalid. */
key->hw_key_idx = 0xff;
goto out_unlock;
}
} else {
slot = key->hw_key_idx;
if (slot == 0xff) {
/* This key was not uploaded into the rx key cache. */
goto out_unlock;
}
bitmap_release_region(priv->used_rxkeys, slot, 0);
algo = 0;
} }
mutex_lock(&priv->conf_mutex);
skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*rxkey), skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*rxkey),
P54_CONTROL_TYPE_RX_KEYCACHE, GFP_ATOMIC); P54_CONTROL_TYPE_RX_KEYCACHE, GFP_KERNEL);
if (!skb) { if (!skb) {
mutex_unlock(&priv->conf_mutex); bitmap_release_region(priv->used_rxkeys, slot, 0);
return -ENOMEM; ret = -ENOSPC;
goto out_unlock;
} }
/* TODO: some devices have 4 more free slots for rx keys */
rxkey = (struct p54_keycache *)skb_put(skb, sizeof(*rxkey)); rxkey = (struct p54_keycache *)skb_put(skb, sizeof(*rxkey));
rxkey->entry = key->keyidx; rxkey->entry = slot;
rxkey->key_id = key->keyidx; rxkey->key_id = key->keyidx;
rxkey->key_type = algo; rxkey->key_type = algo;
if (sta) if (sta)
...@@ -2427,8 +2470,11 @@ static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd, ...@@ -2427,8 +2470,11 @@ static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd,
} }
priv->tx(dev, skb); priv->tx(dev, skb);
key->hw_key_idx = slot;
out_unlock:
mutex_unlock(&priv->conf_mutex); mutex_unlock(&priv->conf_mutex);
return 0; return ret;
} }
#ifdef CONFIG_P54_LEDS #ifdef CONFIG_P54_LEDS
...@@ -2662,6 +2708,7 @@ void p54_free_common(struct ieee80211_hw *dev) ...@@ -2662,6 +2708,7 @@ void p54_free_common(struct ieee80211_hw *dev)
kfree(priv->iq_autocal); kfree(priv->iq_autocal);
kfree(priv->output_limit); kfree(priv->output_limit);
kfree(priv->curve_data); kfree(priv->curve_data);
kfree(priv->used_rxkeys);
#ifdef CONFIG_P54_LEDS #ifdef CONFIG_P54_LEDS
p54_unregister_leds(dev); p54_unregister_leds(dev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment