diff options
-rw-r--r-- | drivers/net/wireless/p54/p54.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/p54/p54common.c | 101 |
2 files changed, 75 insertions, 27 deletions
diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index d6354faaa2bc..7fda1a9e263b 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 cb490584cb8e..7bd4fdf83349 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 | } |
264 | EXPORT_SYMBOL_GPL(p54_parse_firmware); | 284 | 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 | 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 | |||
2475 | out_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); |