Commit a4bf26f3 authored by Johannes Berg's avatar Johannes Berg Committed by Jeff Garzik

[PATCH] ieee80211: enable hw wep where host has to build IV

This patch fixes some of the ieee80211 crypto related code so that
instead of having the host fully do crypto operations, the host_build_iv
flag works properly (for WEP in this patch) which, if turned on,
requires the hardware to do all crypto operations, but the ieee80211
layer builds the IV. The hardware also has to build the ICV.

Previously, the host_build_iv flag couldn't be used at all for WEP, and
not alone (with both host_decrypt and host_encrypt disabled) because the
crypto algorithm wasn't assigned. This is also fixed.

I have tested this patch both in host crypto mode and in hw crypto mode
(with the Broadcom chipset).

[resent, signing digitally caused it to be MIME-junked, sorry]
Signed-Off-By: default avatarJohannes Berg <johannes@sipsolutions.net>
Signed-off-by: default avatarJeff Garzik <jgarzik@pobox.com>
parent df22b8aa
...@@ -75,22 +75,14 @@ static void prism2_wep_deinit(void *priv) ...@@ -75,22 +75,14 @@ static void prism2_wep_deinit(void *priv)
kfree(priv); kfree(priv);
} }
/* Perform WEP encryption on given skb that has at least 4 bytes of headroom /* Add WEP IV/key info to a frame that has at least 4 bytes of headroom */
* for IV and 4 bytes of tailroom for ICV. Both IV and ICV will be transmitted, static int prism2_wep_build_iv(struct sk_buff *skb, int hdr_len, void *priv)
* so the payload length increases with 8 bytes.
*
* WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data))
*/
static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
{ {
struct prism2_wep_data *wep = priv; struct prism2_wep_data *wep = priv;
u32 crc, klen, len; u32 klen, len;
u8 key[WEP_KEY_LEN + 3]; u8 *pos;
u8 *pos, *icv;
struct scatterlist sg; if (skb_headroom(skb) < 4 || skb->len < hdr_len)
if (skb_headroom(skb) < 4 || skb_tailroom(skb) < 4 ||
skb->len < hdr_len)
return -1; return -1;
len = skb->len - hdr_len; len = skb->len - hdr_len;
...@@ -112,15 +104,47 @@ static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv) ...@@ -112,15 +104,47 @@ static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
} }
/* Prepend 24-bit IV to RC4 key and TX frame */ /* Prepend 24-bit IV to RC4 key and TX frame */
*pos++ = key[0] = (wep->iv >> 16) & 0xff; *pos++ = (wep->iv >> 16) & 0xff;
*pos++ = key[1] = (wep->iv >> 8) & 0xff; *pos++ = (wep->iv >> 8) & 0xff;
*pos++ = key[2] = wep->iv & 0xff; *pos++ = wep->iv & 0xff;
*pos++ = wep->key_idx << 6; *pos++ = wep->key_idx << 6;
return 0;
}
/* Perform WEP encryption on given skb that has at least 4 bytes of headroom
* for IV and 4 bytes of tailroom for ICV. Both IV and ICV will be transmitted,
* so the payload length increases with 8 bytes.
*
* WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data))
*/
static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
{
struct prism2_wep_data *wep = priv;
u32 crc, klen, len;
u8 *pos, *icv;
struct scatterlist sg;
u8 key[WEP_KEY_LEN + 3];
/* other checks are in prism2_wep_build_iv */
if (skb_tailroom(skb) < 4)
return -1;
/* add the IV to the frame */
if (prism2_wep_build_iv(skb, hdr_len, priv))
return -1;
/* Copy the IV into the first 3 bytes of the key */
memcpy(key, skb->data + hdr_len, 3);
/* Copy rest of the WEP key (the secret part) */ /* Copy rest of the WEP key (the secret part) */
memcpy(key + 3, wep->key, wep->key_len); memcpy(key + 3, wep->key, wep->key_len);
len = skb->len - hdr_len - 4;
pos = skb->data + hdr_len + 4;
klen = 3 + wep->key_len;
/* Append little-endian CRC32 and encrypt it to produce ICV */ /* Append little-endian CRC32 over only the data and encrypt it to produce ICV */
crc = ~crc32_le(~0, pos, len); crc = ~crc32_le(~0, pos, len);
icv = skb_put(skb, 4); icv = skb_put(skb, 4);
icv[0] = crc; icv[0] = crc;
...@@ -231,6 +255,7 @@ static struct ieee80211_crypto_ops ieee80211_crypt_wep = { ...@@ -231,6 +255,7 @@ static struct ieee80211_crypto_ops ieee80211_crypt_wep = {
.name = "WEP", .name = "WEP",
.init = prism2_wep_init, .init = prism2_wep_init,
.deinit = prism2_wep_deinit, .deinit = prism2_wep_deinit,
.build_iv = prism2_wep_build_iv,
.encrypt_mpdu = prism2_wep_encrypt, .encrypt_mpdu = prism2_wep_encrypt,
.decrypt_mpdu = prism2_wep_decrypt, .decrypt_mpdu = prism2_wep_decrypt,
.encrypt_msdu = NULL, .encrypt_msdu = NULL,
......
...@@ -288,7 +288,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -288,7 +288,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 (host_encrypt) if (host_encrypt || host_build_iv)
fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA | fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA |
IEEE80211_FCTL_PROTECTED; IEEE80211_FCTL_PROTECTED;
else else
......
...@@ -284,7 +284,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee, ...@@ -284,7 +284,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; int host_crypto = ieee->host_encrypt || ieee->host_decrypt || ieee->host_build_iv;
IEEE80211_DEBUG_WX("SET_ENCODE\n"); IEEE80211_DEBUG_WX("SET_ENCODE\n");
......
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