aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZhu Yi <yi.zhu@intel.com>2006-01-19 03:22:32 -0500
committerJohn W. Linville <linville@tuxdriver.com>2006-01-27 17:08:07 -0500
commit9184d9348a7a0e60d70d5f4c23de79fdbc72b9a3 (patch)
treee7211258e23f29de34c39866cfa0933e5d10d2f7
parent41a25c616b3140c388ff6009a1cb0b6b06a10f29 (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.h3
-rw-r--r--net/ieee80211/ieee80211_crypt_ccmp.c8
-rw-r--r--net/ieee80211/ieee80211_crypt_tkip.c53
-rw-r--r--net/ieee80211/ieee80211_crypt_wep.c5
-rw-r--r--net/ieee80211/ieee80211_tx.c4
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
193static int ieee80211_ccmp_hdr(struct sk_buff *skb, int hdr_len, void *priv) 193static 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
273static u8 *ieee80211_tkip_hdr(struct sk_buff *skb, int hdr_len, void *priv) 273static 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
320static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv) 319static 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 */
79static int prism2_wep_build_iv(struct sk_buff *skb, int hdr_len, void *priv) 79static 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