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 /net/ieee80211 | |
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>
Diffstat (limited to 'net/ieee80211')
-rw-r--r-- | net/ieee80211/ieee80211_tx.c | 27 | ||||
-rw-r--r-- | net/ieee80211/ieee80211_wx.c | 50 |
2 files changed, 50 insertions, 27 deletions
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) |