diff options
author | James Ketrenos <jketreno@linux.intel.com> | 2005-09-21 12:53:54 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2005-09-21 23:01:52 -0400 |
commit | f1bf6638af9e9bbbb6fb0b769054fb7db1ae652f (patch) | |
tree | 5cf2dca63f88c1709ae8ee9d913c7f819bfc6ce8 | |
parent | 20d64713ae71c0b0aa06084acbef2244021baaca (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.h | 46 | ||||
-rw-r--r-- | net/ieee80211/ieee80211_tx.c | 27 | ||||
-rw-r--r-- | net/ieee80211/ieee80211_wx.c | 50 |
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 | ||
453 | struct ieee80211_security { | 455 | struct 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 | ||
637 | struct ieee80211_device { | 640 | struct 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) |