diff options
author | Zhu Yi <yi.zhu@intel.com> | 2006-01-19 03:22:32 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2006-01-27 17:08:07 -0500 |
commit | 9184d9348a7a0e60d70d5f4c23de79fdbc72b9a3 (patch) | |
tree | e7211258e23f29de34c39866cfa0933e5d10d2f7 /net/ieee80211/ieee80211_crypt_tkip.c | |
parent | 41a25c616b3140c388ff6009a1cb0b6b06a10f29 (diff) |
[PATCH] ieee80211: Add TKIP crypt->build_iv
This patch adds ieee80211 TKIP build_iv() method to support hardwares
that can do TKIP encryption but relies on ieee80211 layer to build
the IV. It also changes the build_iv() interface to return the key
if possible after the IV is built (this is required by TKIP).
Signed-off-by: Zhu Yi <yi.zhu@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/ieee80211/ieee80211_crypt_tkip.c')
-rw-r--r-- | net/ieee80211/ieee80211_crypt_tkip.c | 53 |
1 files changed, 27 insertions, 26 deletions
diff --git a/net/ieee80211/ieee80211_crypt_tkip.c b/net/ieee80211/ieee80211_crypt_tkip.c index de56a47edb00..93def94c1b32 100644 --- a/net/ieee80211/ieee80211_crypt_tkip.c +++ b/net/ieee80211/ieee80211_crypt_tkip.c | |||
@@ -270,34 +270,33 @@ static void tkip_mixing_phase2(u8 * WEPSeed, const u8 * TK, const u16 * TTAK, | |||
270 | #endif | 270 | #endif |
271 | } | 271 | } |
272 | 272 | ||
273 | static u8 *ieee80211_tkip_hdr(struct sk_buff *skb, int hdr_len, void *priv) | 273 | static int ieee80211_tkip_hdr(struct sk_buff *skb, int hdr_len, |
274 | u8 * rc4key, int keylen, void *priv) | ||
274 | { | 275 | { |
275 | struct ieee80211_tkip_data *tkey = priv; | 276 | struct ieee80211_tkip_data *tkey = priv; |
276 | int len; | 277 | int len; |
277 | u8 *rc4key, *pos, *icv; | 278 | u8 *pos; |
278 | struct ieee80211_hdr_4addr *hdr; | 279 | struct ieee80211_hdr_4addr *hdr; |
279 | u32 crc; | ||
280 | 280 | ||
281 | hdr = (struct ieee80211_hdr_4addr *)skb->data; | 281 | hdr = (struct ieee80211_hdr_4addr *)skb->data; |
282 | 282 | ||
283 | if (skb_headroom(skb) < 8 || skb->len < hdr_len) | 283 | if (skb_headroom(skb) < 8 || skb->len < hdr_len) |
284 | return NULL; | 284 | return -1; |
285 | |||
286 | if (rc4key == NULL || keylen < 16) | ||
287 | return -1; | ||
285 | 288 | ||
286 | if (!tkey->tx_phase1_done) { | 289 | if (!tkey->tx_phase1_done) { |
287 | tkip_mixing_phase1(tkey->tx_ttak, tkey->key, hdr->addr2, | 290 | tkip_mixing_phase1(tkey->tx_ttak, tkey->key, hdr->addr2, |
288 | tkey->tx_iv32); | 291 | tkey->tx_iv32); |
289 | tkey->tx_phase1_done = 1; | 292 | tkey->tx_phase1_done = 1; |
290 | } | 293 | } |
291 | rc4key = kmalloc(16, GFP_ATOMIC); | ||
292 | if (!rc4key) | ||
293 | return NULL; | ||
294 | tkip_mixing_phase2(rc4key, tkey->key, tkey->tx_ttak, tkey->tx_iv16); | 294 | tkip_mixing_phase2(rc4key, tkey->key, tkey->tx_ttak, tkey->tx_iv16); |
295 | 295 | ||
296 | len = skb->len - hdr_len; | 296 | len = skb->len - hdr_len; |
297 | pos = skb_push(skb, 8); | 297 | pos = skb_push(skb, 8); |
298 | memmove(pos, pos + 8, hdr_len); | 298 | memmove(pos, pos + 8, hdr_len); |
299 | pos += hdr_len; | 299 | pos += hdr_len; |
300 | icv = skb_put(skb, 4); | ||
301 | 300 | ||
302 | *pos++ = *rc4key; | 301 | *pos++ = *rc4key; |
303 | *pos++ = *(rc4key + 1); | 302 | *pos++ = *(rc4key + 1); |
@@ -308,28 +307,28 @@ static u8 *ieee80211_tkip_hdr(struct sk_buff *skb, int hdr_len, void *priv) | |||
308 | *pos++ = (tkey->tx_iv32 >> 16) & 0xff; | 307 | *pos++ = (tkey->tx_iv32 >> 16) & 0xff; |
309 | *pos++ = (tkey->tx_iv32 >> 24) & 0xff; | 308 | *pos++ = (tkey->tx_iv32 >> 24) & 0xff; |
310 | 309 | ||
311 | crc = ~crc32_le(~0, pos, len); | 310 | tkey->tx_iv16++; |
312 | icv[0] = crc; | 311 | if (tkey->tx_iv16 == 0) { |
313 | icv[1] = crc >> 8; | 312 | tkey->tx_phase1_done = 0; |
314 | icv[2] = crc >> 16; | 313 | tkey->tx_iv32++; |
315 | icv[3] = crc >> 24; | 314 | } |
316 | 315 | ||
317 | return rc4key; | 316 | return 8; |
318 | } | 317 | } |
319 | 318 | ||
320 | static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv) | 319 | static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv) |
321 | { | 320 | { |
322 | struct ieee80211_tkip_data *tkey = priv; | 321 | struct ieee80211_tkip_data *tkey = priv; |
323 | int len; | 322 | int len; |
324 | const u8 *rc4key; | 323 | u8 rc4key[16], *pos, *icv; |
325 | u8 *pos; | 324 | u32 crc; |
326 | struct scatterlist sg; | 325 | struct scatterlist sg; |
327 | 326 | ||
328 | if (tkey->flags & IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) { | 327 | if (tkey->flags & IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) { |
329 | if (net_ratelimit()) { | 328 | if (net_ratelimit()) { |
330 | struct ieee80211_hdr_4addr *hdr = | 329 | struct ieee80211_hdr_4addr *hdr = |
331 | (struct ieee80211_hdr_4addr *)skb->data; | 330 | (struct ieee80211_hdr_4addr *)skb->data; |
332 | printk(KERN_DEBUG "TKIP countermeasures: dropped " | 331 | printk(KERN_DEBUG ": TKIP countermeasures: dropped " |
333 | "TX packet to " MAC_FMT "\n", | 332 | "TX packet to " MAC_FMT "\n", |
334 | MAC_ARG(hdr->addr1)); | 333 | MAC_ARG(hdr->addr1)); |
335 | } | 334 | } |
@@ -342,22 +341,23 @@ static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv) | |||
342 | len = skb->len - hdr_len; | 341 | len = skb->len - hdr_len; |
343 | pos = skb->data + hdr_len; | 342 | pos = skb->data + hdr_len; |
344 | 343 | ||
345 | rc4key = ieee80211_tkip_hdr(skb, hdr_len, priv); | 344 | if ((ieee80211_tkip_hdr(skb, hdr_len, rc4key, 16, priv)) < 0) |
346 | if (!rc4key) | ||
347 | return -1; | 345 | return -1; |
348 | 346 | ||
347 | icv = skb_put(skb, 4); | ||
348 | |||
349 | crc = ~crc32_le(~0, pos, len); | ||
350 | icv[0] = crc; | ||
351 | icv[1] = crc >> 8; | ||
352 | icv[2] = crc >> 16; | ||
353 | icv[3] = crc >> 24; | ||
354 | |||
349 | crypto_cipher_setkey(tkey->tfm_arc4, rc4key, 16); | 355 | crypto_cipher_setkey(tkey->tfm_arc4, rc4key, 16); |
350 | sg.page = virt_to_page(pos); | 356 | sg.page = virt_to_page(pos); |
351 | sg.offset = offset_in_page(pos); | 357 | sg.offset = offset_in_page(pos); |
352 | sg.length = len + 4; | 358 | sg.length = len + 4; |
353 | crypto_cipher_encrypt(tkey->tfm_arc4, &sg, &sg, len + 4); | 359 | crypto_cipher_encrypt(tkey->tfm_arc4, &sg, &sg, len + 4); |
354 | 360 | ||
355 | tkey->tx_iv16++; | ||
356 | if (tkey->tx_iv16 == 0) { | ||
357 | tkey->tx_phase1_done = 0; | ||
358 | tkey->tx_iv32++; | ||
359 | } | ||
360 | |||
361 | return 0; | 361 | return 0; |
362 | } | 362 | } |
363 | 363 | ||
@@ -378,7 +378,7 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) | |||
378 | 378 | ||
379 | if (tkey->flags & IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) { | 379 | if (tkey->flags & IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) { |
380 | if (net_ratelimit()) { | 380 | if (net_ratelimit()) { |
381 | printk(KERN_DEBUG "TKIP countermeasures: dropped " | 381 | printk(KERN_DEBUG ": TKIP countermeasures: dropped " |
382 | "received packet from " MAC_FMT "\n", | 382 | "received packet from " MAC_FMT "\n", |
383 | MAC_ARG(hdr->addr2)); | 383 | MAC_ARG(hdr->addr2)); |
384 | } | 384 | } |
@@ -694,6 +694,7 @@ static struct ieee80211_crypto_ops ieee80211_crypt_tkip = { | |||
694 | .name = "TKIP", | 694 | .name = "TKIP", |
695 | .init = ieee80211_tkip_init, | 695 | .init = ieee80211_tkip_init, |
696 | .deinit = ieee80211_tkip_deinit, | 696 | .deinit = ieee80211_tkip_deinit, |
697 | .build_iv = ieee80211_tkip_hdr, | ||
697 | .encrypt_mpdu = ieee80211_tkip_encrypt, | 698 | .encrypt_mpdu = ieee80211_tkip_encrypt, |
698 | .decrypt_mpdu = ieee80211_tkip_decrypt, | 699 | .decrypt_mpdu = ieee80211_tkip_decrypt, |
699 | .encrypt_msdu = ieee80211_michael_mic_add, | 700 | .encrypt_msdu = ieee80211_michael_mic_add, |