aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Ketrenos <jketreno@linux.intel.com>2005-09-21 12:53:54 -0400
committerJeff Garzik <jgarzik@pobox.com>2005-09-21 23:01:52 -0400
commitf1bf6638af9e9bbbb6fb0b769054fb7db1ae652f (patch)
tree5cf2dca63f88c1709ae8ee9d913c7f819bfc6ce8
parent20d64713ae71c0b0aa06084acbef2244021baaca (diff)
[PATCH] ieee80211: Hardware crypto and fragmentation offload support
tree 5322d496af90d03ffbec27292dc1a6268a746ede parent 6c9364386ccb786e4a84427ab3ad712f0b7b8904 author James Ketrenos <jketreno@linux.intel.com> 1124432367 -0500 committer James Ketrenos <jketreno@linux.intel.com> 1127311810 -0500 Hardware crypto and fragmentation offload support added (Zhu Yi) Signed-off-by: James Ketrenos <jketreno@linux.intel.com> Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
-rw-r--r--include/net/ieee80211.h46
-rw-r--r--net/ieee80211/ieee80211_tx.c27
-rw-r--r--net/ieee80211/ieee80211_wx.c50
3 files changed, 75 insertions, 48 deletions
diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h
index ed06a9454edc..fa14360dbc9d 100644
--- a/include/net/ieee80211.h
+++ b/include/net/ieee80211.h
@@ -430,31 +430,34 @@ struct ieee80211_device;
430 430
431#include "ieee80211_crypt.h" 431#include "ieee80211_crypt.h"
432 432
433#define SEC_KEY_1 (1<<0) 433#define SEC_KEY_1 (1<<0)
434#define SEC_KEY_2 (1<<1) 434#define SEC_KEY_2 (1<<1)
435#define SEC_KEY_3 (1<<2) 435#define SEC_KEY_3 (1<<2)
436#define SEC_KEY_4 (1<<3) 436#define SEC_KEY_4 (1<<3)
437#define SEC_KEY_MASK (SEC_KEY_1 | SEC_KEY_2 | SEC_KEY_3 | SEC_KEY_4) 437#define SEC_ACTIVE_KEY (1<<4)
438#define SEC_ACTIVE_KEY (1<<4) 438#define SEC_AUTH_MODE (1<<5)
439#define SEC_AUTH_MODE (1<<5) 439#define SEC_UNICAST_GROUP (1<<6)
440#define SEC_UNICAST_GROUP (1<<6) 440#define SEC_LEVEL (1<<7)
441#define SEC_LEVEL (1<<7) 441#define SEC_ENABLED (1<<8)
442#define SEC_ENABLED (1<<8) 442#define SEC_TGI_KEY_RESET (1<<9)
443 443
444#define SEC_LEVEL_0 0 /* None */ 444#define SEC_LEVEL_0 0 /* None */
445#define SEC_LEVEL_1 1 /* WEP 40 and 104 bit */ 445#define SEC_LEVEL_1 1 /* WEP 40 and 104 bit */
446#define SEC_LEVEL_2 2 /* Level 1 + TKIP */ 446#define SEC_LEVEL_2 2 /* Level 1 + TKIP */
447#define SEC_LEVEL_2_CKIP 3 /* Level 1 + CKIP */ 447#define SEC_LEVEL_2_CKIP 3 /* Level 1 + CKIP */
448#define SEC_LEVEL_3 4 /* Level 2 + CCMP */ 448#define SEC_LEVEL_3 4 /* Level 2 + CCMP */
449 449
450#define WEP_KEYS 4 450#define WEP_KEYS 4
451#define WEP_KEY_LEN 13 451#define WEP_KEY_LEN 13
452#define SCM_KEY_LEN 32
453#define SCM_TEMPORAL_KEY_LENGTH 16
452 454
453struct ieee80211_security { 455struct ieee80211_security {
454 u16 active_key:2, 456 u16 active_key:2,
455 enabled:1, auth_mode:2, auth_algo:4, unicast_uses_group:1; 457 enabled:1,
458 auth_mode:2, auth_algo:4, unicast_uses_group:1, encrypt:1;
456 u8 key_sizes[WEP_KEYS]; 459 u8 key_sizes[WEP_KEYS];
457 u8 keys[WEP_KEYS][WEP_KEY_LEN]; 460 u8 keys[WEP_KEYS][SCM_KEY_LEN];
458 u8 level; 461 u8 level;
459 u16 flags; 462 u16 flags;
460} __attribute__ ((packed)); 463} __attribute__ ((packed));
@@ -636,6 +639,7 @@ enum ieee80211_state {
636 639
637struct ieee80211_device { 640struct ieee80211_device {
638 struct net_device *dev; 641 struct net_device *dev;
642 struct ieee80211_security sec;
639 643
640 /* Bookkeeping structures */ 644 /* Bookkeeping structures */
641 struct net_device_stats stats; 645 struct net_device_stats stats;
diff --git a/net/ieee80211/ieee80211_tx.c b/net/ieee80211/ieee80211_tx.c
index 435ef5a73d75..785e76f7e4e9 100644
--- a/net/ieee80211/ieee80211_tx.c
+++ b/net/ieee80211/ieee80211_tx.c
@@ -231,7 +231,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
231 int i, bytes_per_frag, nr_frags, bytes_last_frag, frag_size; 231 int i, bytes_per_frag, nr_frags, bytes_last_frag, frag_size;
232 unsigned long flags; 232 unsigned long flags;
233 struct net_device_stats *stats = &ieee->stats; 233 struct net_device_stats *stats = &ieee->stats;
234 int ether_type, encrypt; 234 int ether_type, encrypt, host_encrypt;
235 int bytes, fc, hdr_len; 235 int bytes, fc, hdr_len;
236 struct sk_buff *skb_frag; 236 struct sk_buff *skb_frag;
237 struct ieee80211_hdr header = { /* Ensure zero initialized */ 237 struct ieee80211_hdr header = { /* Ensure zero initialized */
@@ -262,7 +262,8 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
262 crypt = ieee->crypt[ieee->tx_keyidx]; 262 crypt = ieee->crypt[ieee->tx_keyidx];
263 263
264 encrypt = !(ether_type == ETH_P_PAE && ieee->ieee802_1x) && 264 encrypt = !(ether_type == ETH_P_PAE && ieee->ieee802_1x) &&
265 ieee->host_encrypt && crypt && crypt->ops; 265 ieee->sec.encrypt;
266 host_encrypt = ieee->host_encrypt && encrypt;
266 267
267 if (!encrypt && ieee->ieee802_1x && 268 if (!encrypt && ieee->ieee802_1x &&
268 ieee->drop_unencrypted && ether_type != ETH_P_PAE) { 269 ieee->drop_unencrypted && ether_type != ETH_P_PAE) {
@@ -280,7 +281,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
280 /* Determine total amount of storage required for TXB packets */ 281 /* Determine total amount of storage required for TXB packets */
281 bytes = skb->len + SNAP_SIZE + sizeof(u16); 282 bytes = skb->len + SNAP_SIZE + sizeof(u16);
282 283
283 if (encrypt) 284 if (host_encrypt)
284 fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA | 285 fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA |
285 IEEE80211_FCTL_PROTECTED; 286 IEEE80211_FCTL_PROTECTED;
286 else 287 else
@@ -320,7 +321,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
320 bytes_per_frag -= IEEE80211_FCS_LEN; 321 bytes_per_frag -= IEEE80211_FCS_LEN;
321 322
322 /* Each fragment may need to have room for encryptiong pre/postfix */ 323 /* Each fragment may need to have room for encryptiong pre/postfix */
323 if (encrypt) 324 if (host_encrypt)
324 bytes_per_frag -= crypt->ops->extra_prefix_len + 325 bytes_per_frag -= crypt->ops->extra_prefix_len +
325 crypt->ops->extra_postfix_len; 326 crypt->ops->extra_postfix_len;
326 327
@@ -348,7 +349,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
348 for (i = 0; i < nr_frags; i++) { 349 for (i = 0; i < nr_frags; i++) {
349 skb_frag = txb->fragments[i]; 350 skb_frag = txb->fragments[i];
350 351
351 if (encrypt) 352 if (host_encrypt)
352 skb_reserve(skb_frag, crypt->ops->extra_prefix_len); 353 skb_reserve(skb_frag, crypt->ops->extra_prefix_len);
353 354
354 frag_hdr = (struct ieee80211_hdr *)skb_put(skb_frag, hdr_len); 355 frag_hdr = (struct ieee80211_hdr *)skb_put(skb_frag, hdr_len);
@@ -380,8 +381,22 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
380 381
381 /* Encryption routine will move the header forward in order 382 /* Encryption routine will move the header forward in order
382 * to insert the IV between the header and the payload */ 383 * to insert the IV between the header and the payload */
383 if (encrypt) 384 if (host_encrypt)
384 ieee80211_encrypt_fragment(ieee, skb_frag, hdr_len); 385 ieee80211_encrypt_fragment(ieee, skb_frag, hdr_len);
386
387 /* ipw2200/2915 Hardware encryption doesn't support TKIP MIC */
388 if (!ieee->host_encrypt && encrypt &&
389 (ieee->sec.level == SEC_LEVEL_2) &&
390 crypt && crypt->ops && crypt->ops->encrypt_msdu) {
391 int res = 0;
392 res = crypt->ops->encrypt_msdu(skb_frag, hdr_len,
393 crypt->priv);
394 if (res < 0) {
395 IEEE80211_ERROR("TKIP MIC encryption failed\n");
396 goto failed;
397 }
398 }
399
385 if (ieee->config & 400 if (ieee->config &
386 (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS)) 401 (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS))
387 skb_put(skb_frag, 4); 402 skb_put(skb_frag, 4);
diff --git a/net/ieee80211/ieee80211_wx.c b/net/ieee80211/ieee80211_wx.c
index fc4e1377aba7..f88c8116a23c 100644
--- a/net/ieee80211/ieee80211_wx.c
+++ b/net/ieee80211/ieee80211_wx.c
@@ -278,6 +278,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
278 }; 278 };
279 int i, key, key_provided, len; 279 int i, key, key_provided, len;
280 struct ieee80211_crypt_data **crypt; 280 struct ieee80211_crypt_data **crypt;
281 int host_crypto = ieee->host_encrypt || ieee->host_decrypt;
281 282
282 IEEE80211_DEBUG_WX("SET_ENCODE\n"); 283 IEEE80211_DEBUG_WX("SET_ENCODE\n");
283 284
@@ -318,6 +319,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
318 319
319 if (i == WEP_KEYS) { 320 if (i == WEP_KEYS) {
320 sec.enabled = 0; 321 sec.enabled = 0;
322 sec.encrypt = 0;
321 sec.level = SEC_LEVEL_0; 323 sec.level = SEC_LEVEL_0;
322 sec.flags |= SEC_ENABLED | SEC_LEVEL; 324 sec.flags |= SEC_ENABLED | SEC_LEVEL;
323 } 325 }
@@ -326,6 +328,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
326 } 328 }
327 329
328 sec.enabled = 1; 330 sec.enabled = 1;
331 sec.encrypt = 1;
329 sec.flags |= SEC_ENABLED; 332 sec.flags |= SEC_ENABLED;
330 333
331 if (*crypt != NULL && (*crypt)->ops != NULL && 334 if (*crypt != NULL && (*crypt)->ops != NULL &&
@@ -335,7 +338,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
335 ieee80211_crypt_delayed_deinit(ieee, crypt); 338 ieee80211_crypt_delayed_deinit(ieee, crypt);
336 } 339 }
337 340
338 if (*crypt == NULL) { 341 if (*crypt == NULL && host_crypto) {
339 struct ieee80211_crypt_data *new_crypt; 342 struct ieee80211_crypt_data *new_crypt;
340 343
341 /* take WEP into use */ 344 /* take WEP into use */
@@ -375,31 +378,34 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
375 key, escape_essid(sec.keys[key], len), 378 key, escape_essid(sec.keys[key], len),
376 erq->length, len); 379 erq->length, len);
377 sec.key_sizes[key] = len; 380 sec.key_sizes[key] = len;
378 (*crypt)->ops->set_key(sec.keys[key], len, NULL, 381 if (*crypt)
379 (*crypt)->priv); 382 (*crypt)->ops->set_key(sec.keys[key], len, NULL,
383 (*crypt)->priv);
380 sec.flags |= (1 << key); 384 sec.flags |= (1 << key);
381 /* This ensures a key will be activated if no key is 385 /* This ensures a key will be activated if no key is
382 * explicitely set */ 386 * explicitely set */
383 if (key == sec.active_key) 387 if (key == sec.active_key)
384 sec.flags |= SEC_ACTIVE_KEY; 388 sec.flags |= SEC_ACTIVE_KEY;
389
385 } else { 390 } else {
386 len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN, 391 if (host_crypto) {
387 NULL, (*crypt)->priv); 392 len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN,
388 if (len == 0) { 393 NULL, (*crypt)->priv);
389 /* Set a default key of all 0 */ 394 if (len == 0) {
390 IEEE80211_DEBUG_WX("Setting key %d to all zero.\n", 395 /* Set a default key of all 0 */
391 key); 396 IEEE80211_DEBUG_WX("Setting key %d to all "
392 memset(sec.keys[key], 0, 13); 397 "zero.\n", key);
393 (*crypt)->ops->set_key(sec.keys[key], 13, NULL, 398 memset(sec.keys[key], 0, 13);
394 (*crypt)->priv); 399 (*crypt)->ops->set_key(sec.keys[key], 13, NULL,
395 sec.key_sizes[key] = 13; 400 (*crypt)->priv);
396 sec.flags |= (1 << key); 401 sec.key_sizes[key] = 13;
402 sec.flags |= (1 << key);
403 }
397 } 404 }
398
399 /* No key data - just set the default TX key index */ 405 /* No key data - just set the default TX key index */
400 if (key_provided) { 406 if (key_provided) {
401 IEEE80211_DEBUG_WX 407 IEEE80211_DEBUG_WX("Setting key %d to default Tx "
402 ("Setting key %d to default Tx key.\n", key); 408 "key.\n", key);
403 ieee->tx_keyidx = key; 409 ieee->tx_keyidx = key;
404 sec.active_key = key; 410 sec.active_key = key;
405 sec.flags |= SEC_ACTIVE_KEY; 411 sec.flags |= SEC_ACTIVE_KEY;
@@ -442,6 +448,7 @@ int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
442 struct iw_point *erq = &(wrqu->encoding); 448 struct iw_point *erq = &(wrqu->encoding);
443 int len, key; 449 int len, key;
444 struct ieee80211_crypt_data *crypt; 450 struct ieee80211_crypt_data *crypt;
451 struct ieee80211_security *sec = &ieee->sec;
445 452
446 IEEE80211_DEBUG_WX("GET_ENCODE\n"); 453 IEEE80211_DEBUG_WX("GET_ENCODE\n");
447 454
@@ -456,13 +463,13 @@ int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
456 crypt = ieee->crypt[key]; 463 crypt = ieee->crypt[key];
457 erq->flags = key + 1; 464 erq->flags = key + 1;
458 465
459 if (crypt == NULL || crypt->ops == NULL) { 466 if (!sec->enabled) {
460 erq->length = 0; 467 erq->length = 0;
461 erq->flags |= IW_ENCODE_DISABLED; 468 erq->flags |= IW_ENCODE_DISABLED;
462 return 0; 469 return 0;
463 } 470 }
464 471
465 if (strcmp(crypt->ops->name, "WEP") != 0) { 472 if (sec->level != SEC_LEVEL_1) {
466 /* only WEP is supported with wireless extensions, so just 473 /* only WEP is supported with wireless extensions, so just
467 * report that encryption is used */ 474 * report that encryption is used */
468 erq->length = 0; 475 erq->length = 0;
@@ -470,9 +477,10 @@ int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
470 return 0; 477 return 0;
471 } 478 }
472 479
473 len = crypt->ops->get_key(keybuf, WEP_KEY_LEN, NULL, crypt->priv); 480 len = sec->key_sizes[key];
474 erq->length = (len >= 0 ? len : 0); 481 memcpy(keybuf, sec->keys[key], len);
475 482
483 erq->length = (len >= 0 ? len : 0);
476 erq->flags |= IW_ENCODE_ENABLED; 484 erq->flags |= IW_ENCODE_ENABLED;
477 485
478 if (ieee->open_wep) 486 if (ieee->open_wep)