mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-17 01:04:19 +08:00
[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>
This commit is contained in:
parent
20d64713ae
commit
f1bf6638af
@ -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 {
|
|||||||
|
|
||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
/* 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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
|
|
||||||
/* 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,
|
|||||||
};
|
};
|
||||||
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,
|
|||||||
|
|
||||||
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,
|
|||||||
}
|
}
|
||||||
|
|
||||||
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,
|
|||||||
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,
|
|||||||
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 {
|
|
||||||
len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN,
|
|
||||||
NULL, (*crypt)->priv);
|
|
||||||
if (len == 0) {
|
|
||||||
/* Set a default key of all 0 */
|
|
||||||
IEEE80211_DEBUG_WX("Setting key %d to all zero.\n",
|
|
||||||
key);
|
|
||||||
memset(sec.keys[key], 0, 13);
|
|
||||||
(*crypt)->ops->set_key(sec.keys[key], 13, NULL,
|
|
||||||
(*crypt)->priv);
|
|
||||||
sec.key_sizes[key] = 13;
|
|
||||||
sec.flags |= (1 << key);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (host_crypto) {
|
||||||
|
len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN,
|
||||||
|
NULL, (*crypt)->priv);
|
||||||
|
if (len == 0) {
|
||||||
|
/* Set a default key of all 0 */
|
||||||
|
IEEE80211_DEBUG_WX("Setting key %d to all "
|
||||||
|
"zero.\n", key);
|
||||||
|
memset(sec.keys[key], 0, 13);
|
||||||
|
(*crypt)->ops->set_key(sec.keys[key], 13, NULL,
|
||||||
|
(*crypt)->priv);
|
||||||
|
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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)
|
||||||
|
Loading…
Reference in New Issue
Block a user