aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/p54
diff options
context:
space:
mode:
authorChristian Lamparter <chunkeey@web.de>2009-04-10 21:58:01 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-04-22 16:54:45 -0400
commit6dfe9a884fec67070fc7502ad82f7eb328950b72 (patch)
tree41e23d2b9ddae510e22049af17fa631afba73da4 /drivers/net/wireless/p54
parent492301fb5d12e4a77a1010ad2b6f1ed306014123 (diff)
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: Christian Lamparter <chunkeey@web.de> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/p54')
-rw-r--r--drivers/net/wireless/p54/p54.h1
-rw-r--r--drivers/net/wireless/p54/p54common.c101
2 files changed, 75 insertions, 27 deletions
diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h
index d6354faaa2b..7fda1a9e263 100644
--- a/drivers/net/wireless/p54/p54.h
+++ b/drivers/net/wireless/p54/p54.h
@@ -186,6 +186,7 @@ struct p54_common {
186 /* cryptographic engine information */ 186 /* cryptographic engine information */
187 u8 privacy_caps; 187 u8 privacy_caps;
188 u8 rx_keycache_size; 188 u8 rx_keycache_size;
189 unsigned long *used_rxkeys;
189 190
190 /* LED management */ 191 /* LED management */
191#ifdef CONFIG_MAC80211_LEDS 192#ifdef CONFIG_MAC80211_LEDS
diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c
index cb490584cb8..7bd4fdf8334 100644
--- a/drivers/net/wireless/p54/p54common.c
+++ b/drivers/net/wireless/p54/p54common.c
@@ -249,7 +249,7 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
249 dev->queues = P54_QUEUE_AC_NUM; 249 dev->queues = P54_QUEUE_AC_NUM;
250 } 250 }
251 251
252 if (!modparam_nohwcrypt) 252 if (!modparam_nohwcrypt) {
253 printk(KERN_INFO "%s: cryptographic accelerator " 253 printk(KERN_INFO "%s: cryptographic accelerator "
254 "WEP:%s, TKIP:%s, CCMP:%s\n", 254 "WEP:%s, TKIP:%s, CCMP:%s\n",
255 wiphy_name(dev->wiphy), 255 wiphy_name(dev->wiphy),
@@ -259,6 +259,26 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
259 (priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP) ? 259 (priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP) ?
260 "YES" : "no"); 260 "YES" : "no");
261 261
262 if (priv->rx_keycache_size) {
263 /*
264 * NOTE:
265 *
266 * The firmware provides at most 255 (0 - 254) slots
267 * for keys which are then used to offload decryption.
268 * As a result the 255 entry (aka 0xff) can be used
269 * safely by the driver to mark keys that didn't fit
270 * into the full cache. This trick saves us from
271 * keeping a extra list for uploaded keys.
272 */
273
274 priv->used_rxkeys = kzalloc(BITS_TO_LONGS(
275 priv->rx_keycache_size), GFP_KERNEL);
276
277 if (!priv->used_rxkeys)
278 return -ENOMEM;
279 }
280 }
281
262 return 0; 282 return 0;
263} 283}
264EXPORT_SYMBOL_GPL(p54_parse_firmware); 284EXPORT_SYMBOL_GPL(p54_parse_firmware);
@@ -2355,61 +2375,84 @@ static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd,
2355 struct p54_common *priv = dev->priv; 2375 struct p54_common *priv = dev->priv;
2356 struct sk_buff *skb; 2376 struct sk_buff *skb;
2357 struct p54_keycache *rxkey; 2377 struct p54_keycache *rxkey;
2378 int slot, ret = 0;
2358 u8 algo = 0; 2379 u8 algo = 0;
2359 2380
2360 if (modparam_nohwcrypt) 2381 if (modparam_nohwcrypt)
2361 return -EOPNOTSUPP; 2382 return -EOPNOTSUPP;
2362 2383
2363 if (cmd == DISABLE_KEY) 2384 mutex_lock(&priv->conf_mutex);
2364 algo = 0; 2385 if (cmd == SET_KEY) {
2365 else {
2366 switch (key->alg) { 2386 switch (key->alg) {
2367 case ALG_TKIP: 2387 case ALG_TKIP:
2368 if (!(priv->privacy_caps & (BR_DESC_PRIV_CAP_MICHAEL | 2388 if (!(priv->privacy_caps & (BR_DESC_PRIV_CAP_MICHAEL |
2369 BR_DESC_PRIV_CAP_TKIP))) 2389 BR_DESC_PRIV_CAP_TKIP))) {
2370 return -EOPNOTSUPP; 2390 ret = -EOPNOTSUPP;
2391 goto out_unlock;
2392 }
2371 key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; 2393 key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
2372 algo = P54_CRYPTO_TKIPMICHAEL; 2394 algo = P54_CRYPTO_TKIPMICHAEL;
2373 break; 2395 break;
2374 case ALG_WEP: 2396 case ALG_WEP:
2375 if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_WEP)) 2397 if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_WEP)) {
2376 return -EOPNOTSUPP; 2398 ret = -EOPNOTSUPP;
2399 goto out_unlock;
2400 }
2377 key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; 2401 key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
2378 algo = P54_CRYPTO_WEP; 2402 algo = P54_CRYPTO_WEP;
2379 break; 2403 break;
2380 case ALG_CCMP: 2404 case ALG_CCMP:
2381 if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP)) 2405 if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP)) {
2382 return -EOPNOTSUPP; 2406 ret = -EOPNOTSUPP;
2407 goto out_unlock;
2408 }
2383 key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; 2409 key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
2384 algo = P54_CRYPTO_AESCCMP; 2410 algo = P54_CRYPTO_AESCCMP;
2385 break; 2411 break;
2386 default: 2412 default:
2387 return -EOPNOTSUPP; 2413 ret = -EOPNOTSUPP;
2414 goto out_unlock;
2388 } 2415 }
2389 } 2416 slot = bitmap_find_free_region(priv->used_rxkeys,
2417 priv->rx_keycache_size, 0);
2390 2418
2391 if (key->keyidx > priv->rx_keycache_size) { 2419 if (slot < 0) {
2392 /* 2420 /*
2393 * The device supports the choosen algorithm, but the firmware 2421 * The device supports the choosen algorithm, but the
2394 * does not provide enough key slots to store all of them. 2422 * firmware does not provide enough key slots to store
2395 * So, incoming frames have to be decoded by the mac80211 stack, 2423 * all of them.
2396 * but we can still offload encryption for outgoing frames. 2424 * But encryption offload for outgoing frames is always
2397 */ 2425 * possible, so we just pretend that the upload was
2426 * successful and do the decryption in software.
2427 */
2398 2428
2399 return 0; 2429 /* mark the key as invalid. */
2430 key->hw_key_idx = 0xff;
2431 goto out_unlock;
2432 }
2433 } else {
2434 slot = key->hw_key_idx;
2435
2436 if (slot == 0xff) {
2437 /* This key was not uploaded into the rx key cache. */
2438
2439 goto out_unlock;
2440 }
2441
2442 bitmap_release_region(priv->used_rxkeys, slot, 0);
2443 algo = 0;
2400 } 2444 }
2401 2445
2402 mutex_lock(&priv->conf_mutex);
2403 skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*rxkey), 2446 skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*rxkey),
2404 P54_CONTROL_TYPE_RX_KEYCACHE, GFP_ATOMIC); 2447 P54_CONTROL_TYPE_RX_KEYCACHE, GFP_KERNEL);
2405 if (!skb) { 2448 if (!skb) {
2406 mutex_unlock(&priv->conf_mutex); 2449 bitmap_release_region(priv->used_rxkeys, slot, 0);
2407 return -ENOMEM; 2450 ret = -ENOSPC;
2451 goto out_unlock;
2408 } 2452 }
2409 2453
2410 /* TODO: some devices have 4 more free slots for rx keys */
2411 rxkey = (struct p54_keycache *)skb_put(skb, sizeof(*rxkey)); 2454 rxkey = (struct p54_keycache *)skb_put(skb, sizeof(*rxkey));
2412 rxkey->entry = key->keyidx; 2455 rxkey->entry = slot;
2413 rxkey->key_id = key->keyidx; 2456 rxkey->key_id = key->keyidx;
2414 rxkey->key_type = algo; 2457 rxkey->key_type = algo;
2415 if (sta) 2458 if (sta)
@@ -2427,8 +2470,11 @@ static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd,
2427 } 2470 }
2428 2471
2429 priv->tx(dev, skb); 2472 priv->tx(dev, skb);
2473 key->hw_key_idx = slot;
2474
2475out_unlock:
2430 mutex_unlock(&priv->conf_mutex); 2476 mutex_unlock(&priv->conf_mutex);
2431 return 0; 2477 return ret;
2432} 2478}
2433 2479
2434#ifdef CONFIG_P54_LEDS 2480#ifdef CONFIG_P54_LEDS
@@ -2662,6 +2708,7 @@ void p54_free_common(struct ieee80211_hw *dev)
2662 kfree(priv->iq_autocal); 2708 kfree(priv->iq_autocal);
2663 kfree(priv->output_limit); 2709 kfree(priv->output_limit);
2664 kfree(priv->curve_data); 2710 kfree(priv->curve_data);
2711 kfree(priv->used_rxkeys);
2665 2712
2666#ifdef CONFIG_P54_LEDS 2713#ifdef CONFIG_P54_LEDS
2667 p54_unregister_leds(dev); 2714 p54_unregister_leds(dev);