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 | |
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>
-rw-r--r-- | include/net/ieee80211_crypt.h | 3 | ||||
-rw-r--r-- | net/ieee80211/ieee80211_crypt_ccmp.c | 8 | ||||
-rw-r--r-- | net/ieee80211/ieee80211_crypt_tkip.c | 53 | ||||
-rw-r--r-- | net/ieee80211/ieee80211_crypt_wep.c | 5 | ||||
-rw-r--r-- | net/ieee80211/ieee80211_tx.c | 4 |
5 files changed, 41 insertions, 32 deletions
diff --git a/include/net/ieee80211_crypt.h b/include/net/ieee80211_crypt.h index cd82c3e998e4..eb476414fd72 100644 --- a/include/net/ieee80211_crypt.h +++ b/include/net/ieee80211_crypt.h | |||
@@ -47,7 +47,8 @@ struct ieee80211_crypto_ops { | |||
47 | /* deinitialize crypto context and free allocated private data */ | 47 | /* deinitialize crypto context and free allocated private data */ |
48 | void (*deinit) (void *priv); | 48 | void (*deinit) (void *priv); |
49 | 49 | ||
50 | int (*build_iv) (struct sk_buff * skb, int hdr_len, void *priv); | 50 | int (*build_iv) (struct sk_buff * skb, int hdr_len, |
51 | u8 *key, int keylen, void *priv); | ||
51 | 52 | ||
52 | /* encrypt/decrypt return < 0 on error or >= 0 on success. The return | 53 | /* encrypt/decrypt return < 0 on error or >= 0 on success. The return |
53 | * value from decrypt_mpdu is passed as the keyidx value for | 54 | * value from decrypt_mpdu is passed as the keyidx value for |
diff --git a/net/ieee80211/ieee80211_crypt_ccmp.c b/net/ieee80211/ieee80211_crypt_ccmp.c index 470221728503..097bcea2129f 100644 --- a/net/ieee80211/ieee80211_crypt_ccmp.c +++ b/net/ieee80211/ieee80211_crypt_ccmp.c | |||
@@ -190,7 +190,8 @@ static void ccmp_init_blocks(struct crypto_tfm *tfm, | |||
190 | ieee80211_ccmp_aes_encrypt(tfm, b0, s0); | 190 | ieee80211_ccmp_aes_encrypt(tfm, b0, s0); |
191 | } | 191 | } |
192 | 192 | ||
193 | static int ieee80211_ccmp_hdr(struct sk_buff *skb, int hdr_len, void *priv) | 193 | static int ieee80211_ccmp_hdr(struct sk_buff *skb, int hdr_len, |
194 | u8 *aeskey, int keylen, void *priv) | ||
194 | { | 195 | { |
195 | struct ieee80211_ccmp_data *key = priv; | 196 | struct ieee80211_ccmp_data *key = priv; |
196 | int i; | 197 | int i; |
@@ -199,6 +200,9 @@ static int ieee80211_ccmp_hdr(struct sk_buff *skb, int hdr_len, void *priv) | |||
199 | if (skb_headroom(skb) < CCMP_HDR_LEN || skb->len < hdr_len) | 200 | if (skb_headroom(skb) < CCMP_HDR_LEN || skb->len < hdr_len) |
200 | return -1; | 201 | return -1; |
201 | 202 | ||
203 | if (aeskey != NULL && keylen >= CCMP_TK_LEN) | ||
204 | memcpy(aeskey, key->key, CCMP_TK_LEN); | ||
205 | |||
202 | pos = skb_push(skb, CCMP_HDR_LEN); | 206 | pos = skb_push(skb, CCMP_HDR_LEN); |
203 | memmove(pos, pos + CCMP_HDR_LEN, hdr_len); | 207 | memmove(pos, pos + CCMP_HDR_LEN, hdr_len); |
204 | pos += hdr_len; | 208 | pos += hdr_len; |
@@ -238,7 +242,7 @@ static int ieee80211_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv) | |||
238 | return -1; | 242 | return -1; |
239 | 243 | ||
240 | data_len = skb->len - hdr_len; | 244 | data_len = skb->len - hdr_len; |
241 | len = ieee80211_ccmp_hdr(skb, hdr_len, priv); | 245 | len = ieee80211_ccmp_hdr(skb, hdr_len, NULL, 0, priv); |
242 | if (len < 0) | 246 | if (len < 0) |
243 | return -1; | 247 | return -1; |
244 | 248 | ||
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, |
diff --git a/net/ieee80211/ieee80211_crypt_wep.c b/net/ieee80211/ieee80211_crypt_wep.c index f8dca31be5dd..649e581fa565 100644 --- a/net/ieee80211/ieee80211_crypt_wep.c +++ b/net/ieee80211/ieee80211_crypt_wep.c | |||
@@ -76,7 +76,8 @@ static void prism2_wep_deinit(void *priv) | |||
76 | } | 76 | } |
77 | 77 | ||
78 | /* Add WEP IV/key info to a frame that has at least 4 bytes of headroom */ | 78 | /* Add WEP IV/key info to a frame that has at least 4 bytes of headroom */ |
79 | static int prism2_wep_build_iv(struct sk_buff *skb, int hdr_len, void *priv) | 79 | static int prism2_wep_build_iv(struct sk_buff *skb, int hdr_len, |
80 | u8 *key, int keylen, void *priv) | ||
80 | { | 81 | { |
81 | struct prism2_wep_data *wep = priv; | 82 | struct prism2_wep_data *wep = priv; |
82 | u32 klen, len; | 83 | u32 klen, len; |
@@ -131,7 +132,7 @@ static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv) | |||
131 | return -1; | 132 | return -1; |
132 | 133 | ||
133 | /* add the IV to the frame */ | 134 | /* add the IV to the frame */ |
134 | if (prism2_wep_build_iv(skb, hdr_len, priv)) | 135 | if (prism2_wep_build_iv(skb, hdr_len, NULL, 0, priv)) |
135 | return -1; | 136 | return -1; |
136 | 137 | ||
137 | /* Copy the IV into the first 3 bytes of the key */ | 138 | /* Copy the IV into the first 3 bytes of the key */ |
diff --git a/net/ieee80211/ieee80211_tx.c b/net/ieee80211/ieee80211_tx.c index 0949803b9c7d..8b4332f53394 100644 --- a/net/ieee80211/ieee80211_tx.c +++ b/net/ieee80211/ieee80211_tx.c | |||
@@ -470,7 +470,9 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) | |||
470 | atomic_inc(&crypt->refcnt); | 470 | atomic_inc(&crypt->refcnt); |
471 | if (crypt->ops->build_iv) | 471 | if (crypt->ops->build_iv) |
472 | crypt->ops->build_iv(skb_frag, hdr_len, | 472 | crypt->ops->build_iv(skb_frag, hdr_len, |
473 | crypt->priv); | 473 | ieee->sec.keys[ieee->sec.active_key], |
474 | ieee->sec.key_sizes[ieee->sec.active_key], | ||
475 | crypt->priv); | ||
474 | atomic_dec(&crypt->refcnt); | 476 | atomic_dec(&crypt->refcnt); |
475 | } | 477 | } |
476 | 478 | ||