Commit f1bf6638 authored by James Ketrenos's avatar James Ketrenos Committed by Jeff Garzik

[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: default avatarJames Ketrenos <jketreno@linux.intel.com>
Signed-off-by: default avatarJeff Garzik <jgarzik@pobox.com>
parent 20d64713
...@@ -430,31 +430,34 @@ struct ieee80211_device; ...@@ -430,31 +430,34 @@ struct ieee80211_device;
#include "ieee80211_crypt.h" #include "ieee80211_crypt.h"
#define SEC_KEY_1 (1<<0) #define SEC_KEY_1 (1<<0)
#define SEC_KEY_2 (1<<1) #define SEC_KEY_2 (1<<1)
#define SEC_KEY_3 (1<<2) #define SEC_KEY_3 (1<<2)
#define SEC_KEY_4 (1<<3) #define SEC_KEY_4 (1<<3)
#define SEC_KEY_MASK (SEC_KEY_1 | SEC_KEY_2 | SEC_KEY_3 | SEC_KEY_4) #define SEC_ACTIVE_KEY (1<<4)
#define SEC_ACTIVE_KEY (1<<4) #define SEC_AUTH_MODE (1<<5)
#define SEC_AUTH_MODE (1<<5) #define SEC_UNICAST_GROUP (1<<6)
#define SEC_UNICAST_GROUP (1<<6) #define SEC_LEVEL (1<<7)
#define SEC_LEVEL (1<<7) #define SEC_ENABLED (1<<8)
#define SEC_ENABLED (1<<8) #define SEC_TGI_KEY_RESET (1<<9)
#define SEC_LEVEL_0 0 /* None */ #define SEC_LEVEL_0 0 /* None */
#define SEC_LEVEL_1 1 /* WEP 40 and 104 bit */ #define SEC_LEVEL_1 1 /* WEP 40 and 104 bit */
#define SEC_LEVEL_2 2 /* Level 1 + TKIP */ #define SEC_LEVEL_2 2 /* Level 1 + TKIP */
#define SEC_LEVEL_2_CKIP 3 /* Level 1 + CKIP */ #define SEC_LEVEL_2_CKIP 3 /* Level 1 + CKIP */
#define SEC_LEVEL_3 4 /* Level 2 + CCMP */ #define SEC_LEVEL_3 4 /* Level 2 + CCMP */
#define WEP_KEYS 4 #define WEP_KEYS 4
#define WEP_KEY_LEN 13 #define WEP_KEY_LEN 13
#define SCM_KEY_LEN 32
#define SCM_TEMPORAL_KEY_LENGTH 16
struct ieee80211_security { struct ieee80211_security {
u16 active_key:2, u16 active_key:2,
enabled:1, auth_mode:2, auth_algo:4, unicast_uses_group:1; enabled:1,
auth_mode:2, auth_algo:4, unicast_uses_group:1, encrypt:1;
u8 key_sizes[WEP_KEYS]; u8 key_sizes[WEP_KEYS];
u8 keys[WEP_KEYS][WEP_KEY_LEN]; u8 keys[WEP_KEYS][SCM_KEY_LEN];
u8 level; u8 level;
u16 flags; u16 flags;
} __attribute__ ((packed)); } __attribute__ ((packed));
...@@ -636,6 +639,7 @@ enum ieee80211_state { ...@@ -636,6 +639,7 @@ enum ieee80211_state {
struct ieee80211_device { struct ieee80211_device {
struct net_device *dev; struct net_device *dev;
struct ieee80211_security sec;
/* Bookkeeping structures */ /* Bookkeeping structures */
struct net_device_stats stats; struct net_device_stats stats;
......
...@@ -231,7 +231,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -231,7 +231,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
int i, bytes_per_frag, nr_frags, bytes_last_frag, frag_size; int i, bytes_per_frag, nr_frags, bytes_last_frag, frag_size;
unsigned long flags; unsigned long flags;
struct net_device_stats *stats = &ieee->stats; struct net_device_stats *stats = &ieee->stats;
int ether_type, encrypt; int ether_type, encrypt, host_encrypt;
int bytes, fc, hdr_len; int bytes, fc, hdr_len;
struct sk_buff *skb_frag; struct sk_buff *skb_frag;
struct ieee80211_hdr header = { /* Ensure zero initialized */ struct ieee80211_hdr header = { /* Ensure zero initialized */
...@@ -262,7 +262,8 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -262,7 +262,8 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
crypt = ieee->crypt[ieee->tx_keyidx]; crypt = ieee->crypt[ieee->tx_keyidx];
encrypt = !(ether_type == ETH_P_PAE && ieee->ieee802_1x) && encrypt = !(ether_type == ETH_P_PAE && ieee->ieee802_1x) &&
ieee->host_encrypt && crypt && crypt->ops; ieee->sec.encrypt;
host_encrypt = ieee->host_encrypt && encrypt;
if (!encrypt && ieee->ieee802_1x && if (!encrypt && ieee->ieee802_1x &&
ieee->drop_unencrypted && ether_type != ETH_P_PAE) { ieee->drop_unencrypted && ether_type != ETH_P_PAE) {
...@@ -280,7 +281,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -280,7 +281,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
/* Determine total amount of storage required for TXB packets */ /* Determine total amount of storage required for TXB packets */
bytes = skb->len + SNAP_SIZE + sizeof(u16); bytes = skb->len + SNAP_SIZE + sizeof(u16);
if (encrypt) if (host_encrypt)
fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA | fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA |
IEEE80211_FCTL_PROTECTED; IEEE80211_FCTL_PROTECTED;
else else
...@@ -320,7 +321,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -320,7 +321,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
bytes_per_frag -= IEEE80211_FCS_LEN; bytes_per_frag -= IEEE80211_FCS_LEN;
/* Each fragment may need to have room for encryptiong pre/postfix */ /* Each fragment may need to have room for encryptiong pre/postfix */
if (encrypt) if (host_encrypt)
bytes_per_frag -= crypt->ops->extra_prefix_len + bytes_per_frag -= crypt->ops->extra_prefix_len +
crypt->ops->extra_postfix_len; crypt->ops->extra_postfix_len;
...@@ -348,7 +349,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -348,7 +349,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
for (i = 0; i < nr_frags; i++) { for (i = 0; i < nr_frags; i++) {
skb_frag = txb->fragments[i]; skb_frag = txb->fragments[i];
if (encrypt) if (host_encrypt)
skb_reserve(skb_frag, crypt->ops->extra_prefix_len); skb_reserve(skb_frag, crypt->ops->extra_prefix_len);
frag_hdr = (struct ieee80211_hdr *)skb_put(skb_frag, hdr_len); 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,8 +381,22 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
/* Encryption routine will move the header forward in order /* Encryption routine will move the header forward in order
* to insert the IV between the header and the payload */ * to insert the IV between the header and the payload */
if (encrypt) if (host_encrypt)
ieee80211_encrypt_fragment(ieee, skb_frag, hdr_len); ieee80211_encrypt_fragment(ieee, skb_frag, hdr_len);
/* ipw2200/2915 Hardware encryption doesn't support TKIP MIC */
if (!ieee->host_encrypt && encrypt &&
(ieee->sec.level == SEC_LEVEL_2) &&
crypt && crypt->ops && crypt->ops->encrypt_msdu) {
int res = 0;
res = crypt->ops->encrypt_msdu(skb_frag, hdr_len,
crypt->priv);
if (res < 0) {
IEEE80211_ERROR("TKIP MIC encryption failed\n");
goto failed;
}
}
if (ieee->config & if (ieee->config &
(CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS)) (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS))
skb_put(skb_frag, 4); skb_put(skb_frag, 4);
......
...@@ -278,6 +278,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee, ...@@ -278,6 +278,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
}; };
int i, key, key_provided, len; int i, key, key_provided, len;
struct ieee80211_crypt_data **crypt; struct ieee80211_crypt_data **crypt;
int host_crypto = ieee->host_encrypt || ieee->host_decrypt;
IEEE80211_DEBUG_WX("SET_ENCODE\n"); IEEE80211_DEBUG_WX("SET_ENCODE\n");
...@@ -318,6 +319,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee, ...@@ -318,6 +319,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
if (i == WEP_KEYS) { if (i == WEP_KEYS) {
sec.enabled = 0; sec.enabled = 0;
sec.encrypt = 0;
sec.level = SEC_LEVEL_0; sec.level = SEC_LEVEL_0;
sec.flags |= SEC_ENABLED | SEC_LEVEL; sec.flags |= SEC_ENABLED | SEC_LEVEL;
} }
...@@ -326,6 +328,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee, ...@@ -326,6 +328,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
} }
sec.enabled = 1; sec.enabled = 1;
sec.encrypt = 1;
sec.flags |= SEC_ENABLED; sec.flags |= SEC_ENABLED;
if (*crypt != NULL && (*crypt)->ops != NULL && if (*crypt != NULL && (*crypt)->ops != NULL &&
...@@ -335,7 +338,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee, ...@@ -335,7 +338,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
ieee80211_crypt_delayed_deinit(ieee, crypt); ieee80211_crypt_delayed_deinit(ieee, crypt);
} }
if (*crypt == NULL) { if (*crypt == NULL && host_crypto) {
struct ieee80211_crypt_data *new_crypt; struct ieee80211_crypt_data *new_crypt;
/* take WEP into use */ /* take WEP into use */
...@@ -375,31 +378,34 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee, ...@@ -375,31 +378,34 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
key, escape_essid(sec.keys[key], len), key, escape_essid(sec.keys[key], len),
erq->length, len); erq->length, len);
sec.key_sizes[key] = len; sec.key_sizes[key] = len;
(*crypt)->ops->set_key(sec.keys[key], len, NULL, if (*crypt)
(*crypt)->priv); (*crypt)->ops->set_key(sec.keys[key], len, NULL,
(*crypt)->priv);
sec.flags |= (1 << key); sec.flags |= (1 << key);
/* This ensures a key will be activated if no key is /* This ensures a key will be activated if no key is
* explicitely set */ * explicitely set */
if (key == sec.active_key) if (key == sec.active_key)
sec.flags |= SEC_ACTIVE_KEY; sec.flags |= SEC_ACTIVE_KEY;
} else { } else {
len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN, if (host_crypto) {
NULL, (*crypt)->priv); len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN,
if (len == 0) { NULL, (*crypt)->priv);
/* Set a default key of all 0 */ if (len == 0) {
IEEE80211_DEBUG_WX("Setting key %d to all zero.\n", /* Set a default key of all 0 */
key); IEEE80211_DEBUG_WX("Setting key %d to all "
memset(sec.keys[key], 0, 13); "zero.\n", key);
(*crypt)->ops->set_key(sec.keys[key], 13, NULL, memset(sec.keys[key], 0, 13);
(*crypt)->priv); (*crypt)->ops->set_key(sec.keys[key], 13, NULL,
sec.key_sizes[key] = 13; (*crypt)->priv);
sec.flags |= (1 << key); sec.key_sizes[key] = 13;
sec.flags |= (1 << key);
}
} }
/* No key data - just set the default TX key index */ /* No key data - just set the default TX key index */
if (key_provided) { if (key_provided) {
IEEE80211_DEBUG_WX IEEE80211_DEBUG_WX("Setting key %d to default Tx "
("Setting key %d to default Tx key.\n", key); "key.\n", key);
ieee->tx_keyidx = key; ieee->tx_keyidx = key;
sec.active_key = key; sec.active_key = key;
sec.flags |= SEC_ACTIVE_KEY; sec.flags |= SEC_ACTIVE_KEY;
...@@ -442,6 +448,7 @@ int ieee80211_wx_get_encode(struct ieee80211_device *ieee, ...@@ -442,6 +448,7 @@ int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
struct iw_point *erq = &(wrqu->encoding); struct iw_point *erq = &(wrqu->encoding);
int len, key; int len, key;
struct ieee80211_crypt_data *crypt; struct ieee80211_crypt_data *crypt;
struct ieee80211_security *sec = &ieee->sec;
IEEE80211_DEBUG_WX("GET_ENCODE\n"); IEEE80211_DEBUG_WX("GET_ENCODE\n");
...@@ -456,13 +463,13 @@ int ieee80211_wx_get_encode(struct ieee80211_device *ieee, ...@@ -456,13 +463,13 @@ int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
crypt = ieee->crypt[key]; crypt = ieee->crypt[key];
erq->flags = key + 1; erq->flags = key + 1;
if (crypt == NULL || crypt->ops == NULL) { if (!sec->enabled) {
erq->length = 0; erq->length = 0;
erq->flags |= IW_ENCODE_DISABLED; erq->flags |= IW_ENCODE_DISABLED;
return 0; return 0;
} }
if (strcmp(crypt->ops->name, "WEP") != 0) { if (sec->level != SEC_LEVEL_1) {
/* only WEP is supported with wireless extensions, so just /* only WEP is supported with wireless extensions, so just
* report that encryption is used */ * report that encryption is used */
erq->length = 0; erq->length = 0;
...@@ -470,9 +477,10 @@ int ieee80211_wx_get_encode(struct ieee80211_device *ieee, ...@@ -470,9 +477,10 @@ int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
return 0; return 0;
} }
len = crypt->ops->get_key(keybuf, WEP_KEY_LEN, NULL, crypt->priv); len = sec->key_sizes[key];
erq->length = (len >= 0 ? len : 0); memcpy(keybuf, sec->keys[key], len);
erq->length = (len >= 0 ? len : 0);
erq->flags |= IW_ENCODE_ENABLED; erq->flags |= IW_ENCODE_ENABLED;
if (ieee->open_wep) if (ieee->open_wep)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment