aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Ketrenos <jketreno@linux.intel.com>2005-09-21 12:58:49 -0400
committerJeff Garzik <jgarzik@pobox.com>2005-09-22 15:39:41 -0400
commit31b59eaee8f8ec29d8cb6ac0c8eed086689d8030 (patch)
tree5ab119a07e98aaf623dc8ce6f04f7b3403b6b971
parent31696160c7415b5a7efa650c7f1ca5c9623f5d8f (diff)
[PATCH] ieee80211: Added handle_deauth() callback, enhanced tkip/ccmp support of varying hw/sw offload
tree de81b55e78e85997642c651ea677078d0554a14f parent c8030da8c159f8b82712172a6748a42523aea83a author James Ketrenos <jketreno@linux.intel.com> 1127104380 -0500 committer James Ketrenos <jketreno@linux.intel.com> 1127315225 -0500 Added handle_deauth() callback. Enhanced crypt_{tkip,ccmp} to support varying splits of HW/SW offload. Changed channel freq to u32 from u16. Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
-rw-r--r--include/net/ieee80211.h5
-rw-r--r--include/net/ieee80211_crypt.h2
-rw-r--r--net/ieee80211/ieee80211_crypt_ccmp.c41
-rw-r--r--net/ieee80211/ieee80211_crypt_tkip.c60
-rw-r--r--net/ieee80211/ieee80211_rx.c6
-rw-r--r--net/ieee80211/ieee80211_tx.c18
6 files changed, 99 insertions, 33 deletions
diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h
index 4a1340b8341c..220a9e3c91fa 100644
--- a/include/net/ieee80211.h
+++ b/include/net/ieee80211.h
@@ -808,7 +808,7 @@ enum {
808}; 808};
809 809
810struct ieee80211_channel { 810struct ieee80211_channel {
811 u16 freq; 811 u32 freq;
812 u8 channel; 812 u8 channel;
813 u8 flags; 813 u8 flags;
814 u8 max_power; 814 u8 max_power;
@@ -862,6 +862,7 @@ struct ieee80211_device {
862 int host_mc_decrypt; 862 int host_mc_decrypt;
863 863
864 int host_open_frag; 864 int host_open_frag;
865 int host_build_iv;
865 int ieee802_1x; /* is IEEE 802.1X used */ 866 int ieee802_1x; /* is IEEE 802.1X used */
866 867
867 /* WPA data */ 868 /* WPA data */
@@ -914,6 +915,8 @@ struct ieee80211_device {
914 /* Typical STA methods */ 915 /* Typical STA methods */
915 int (*handle_auth) (struct net_device * dev, 916 int (*handle_auth) (struct net_device * dev,
916 struct ieee80211_auth * auth); 917 struct ieee80211_auth * auth);
918 int (*handle_deauth) (struct net_device * dev,
919 struct ieee80211_auth * auth);
917 int (*handle_disassoc) (struct net_device * dev, 920 int (*handle_disassoc) (struct net_device * dev,
918 struct ieee80211_disassoc * assoc); 921 struct ieee80211_disassoc * assoc);
919 int (*handle_beacon) (struct net_device * dev, 922 int (*handle_beacon) (struct net_device * dev,
diff --git a/include/net/ieee80211_crypt.h b/include/net/ieee80211_crypt.h
index 24e4912a263a..daf3b2c6b038 100644
--- a/include/net/ieee80211_crypt.h
+++ b/include/net/ieee80211_crypt.h
@@ -36,6 +36,8 @@ struct ieee80211_crypto_ops {
36 /* deinitialize crypto context and free allocated private data */ 36 /* deinitialize crypto context and free allocated private data */
37 void (*deinit) (void *priv); 37 void (*deinit) (void *priv);
38 38
39 int (*build_iv) (struct sk_buff * skb, int hdr_len, void *priv);
40
39 /* encrypt/decrypt return < 0 on error or >= 0 on success. The return 41 /* encrypt/decrypt return < 0 on error or >= 0 on success. The return
40 * value from decrypt_mpdu is passed as the keyidx value for 42 * value from decrypt_mpdu is passed as the keyidx value for
41 * decrypt_msdu. skb must have enough head and tail room for the 43 * decrypt_msdu. skb must have enough head and tail room for the
diff --git a/net/ieee80211/ieee80211_crypt_ccmp.c b/net/ieee80211/ieee80211_crypt_ccmp.c
index a3dc5712b98b..081d8575dbb1 100644
--- a/net/ieee80211/ieee80211_crypt_ccmp.c
+++ b/net/ieee80211/ieee80211_crypt_ccmp.c
@@ -191,26 +191,18 @@ static void ccmp_init_blocks(struct crypto_tfm *tfm,
191 ieee80211_ccmp_aes_encrypt(tfm, b0, s0); 191 ieee80211_ccmp_aes_encrypt(tfm, b0, s0);
192} 192}
193 193
194static int ieee80211_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv) 194static int ieee80211_ccmp_hdr(struct sk_buff *skb, int hdr_len, void *priv)
195{ 195{
196 struct ieee80211_ccmp_data *key = priv; 196 struct ieee80211_ccmp_data *key = priv;
197 int data_len, i, blocks, last, len; 197 int i;
198 u8 *pos, *mic; 198 u8 *pos;
199 struct ieee80211_hdr_4addr *hdr;
200 u8 *b0 = key->tx_b0;
201 u8 *b = key->tx_b;
202 u8 *e = key->tx_e;
203 u8 *s0 = key->tx_s0;
204 199
205 if (skb_headroom(skb) < CCMP_HDR_LEN || 200 if (skb_headroom(skb) < CCMP_HDR_LEN || skb->len < hdr_len)
206 skb_tailroom(skb) < CCMP_MIC_LEN || skb->len < hdr_len)
207 return -1; 201 return -1;
208 202
209 data_len = skb->len - hdr_len;
210 pos = skb_push(skb, CCMP_HDR_LEN); 203 pos = skb_push(skb, CCMP_HDR_LEN);
211 memmove(pos, pos + CCMP_HDR_LEN, hdr_len); 204 memmove(pos, pos + CCMP_HDR_LEN, hdr_len);
212 pos += hdr_len; 205 pos += hdr_len;
213 mic = skb_put(skb, CCMP_MIC_LEN);
214 206
215 i = CCMP_PN_LEN - 1; 207 i = CCMP_PN_LEN - 1;
216 while (i >= 0) { 208 while (i >= 0) {
@@ -229,6 +221,30 @@ static int ieee80211_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
229 *pos++ = key->tx_pn[1]; 221 *pos++ = key->tx_pn[1];
230 *pos++ = key->tx_pn[0]; 222 *pos++ = key->tx_pn[0];
231 223
224 return CCMP_HDR_LEN;
225}
226
227static int ieee80211_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
228{
229 struct ieee80211_ccmp_data *key = priv;
230 int data_len, i, blocks, last, len;
231 u8 *pos, *mic;
232 struct ieee80211_hdr_4addr *hdr;
233 u8 *b0 = key->tx_b0;
234 u8 *b = key->tx_b;
235 u8 *e = key->tx_e;
236 u8 *s0 = key->tx_s0;
237
238 if (skb_tailroom(skb) < CCMP_MIC_LEN || skb->len < hdr_len)
239 return -1;
240
241 data_len = skb->len - hdr_len;
242 len = ieee80211_ccmp_hdr(skb, hdr_len, priv);
243 if (len < 0)
244 return -1;
245
246 pos = skb->data + hdr_len + CCMP_HDR_LEN;
247 mic = skb_put(skb, CCMP_MIC_LEN);
232 hdr = (struct ieee80211_hdr_4addr *)skb->data; 248 hdr = (struct ieee80211_hdr_4addr *)skb->data;
233 ccmp_init_blocks(key->tfm, hdr, key->tx_pn, data_len, b0, b, s0); 249 ccmp_init_blocks(key->tfm, hdr, key->tx_pn, data_len, b0, b, s0);
234 250
@@ -429,6 +445,7 @@ static struct ieee80211_crypto_ops ieee80211_crypt_ccmp = {
429 .name = "CCMP", 445 .name = "CCMP",
430 .init = ieee80211_ccmp_init, 446 .init = ieee80211_ccmp_init,
431 .deinit = ieee80211_ccmp_deinit, 447 .deinit = ieee80211_ccmp_deinit,
448 .build_iv = ieee80211_ccmp_hdr,
432 .encrypt_mpdu = ieee80211_ccmp_encrypt, 449 .encrypt_mpdu = ieee80211_ccmp_encrypt,
433 .decrypt_mpdu = ieee80211_ccmp_decrypt, 450 .decrypt_mpdu = ieee80211_ccmp_decrypt,
434 .encrypt_msdu = NULL, 451 .encrypt_msdu = NULL,
diff --git a/net/ieee80211/ieee80211_crypt_tkip.c b/net/ieee80211/ieee80211_crypt_tkip.c
index 21022f195bab..e0733050ae71 100644
--- a/net/ieee80211/ieee80211_crypt_tkip.c
+++ b/net/ieee80211/ieee80211_crypt_tkip.c
@@ -260,35 +260,27 @@ static void tkip_mixing_phase2(u8 * WEPSeed, const u8 * TK, const u16 * TTAK,
260#endif 260#endif
261} 261}
262 262
263static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv) 263static u8 *ieee80211_tkip_hdr(struct sk_buff *skb, int hdr_len, void *priv)
264{ 264{
265 struct ieee80211_tkip_data *tkey = priv; 265 struct ieee80211_tkip_data *tkey = priv;
266 int len; 266 int len;
267 u8 rc4key[16], *pos, *icv; 267 u8 *rc4key, *pos, *icv;
268 struct ieee80211_hdr_4addr *hdr; 268 struct ieee80211_hdr_4addr *hdr;
269 u32 crc; 269 u32 crc;
270 struct scatterlist sg;
271 270
272 hdr = (struct ieee80211_hdr_4addr *)skb->data; 271 hdr = (struct ieee80211_hdr_4addr *)skb->data;
273 272
274 if (tkey->ieee->tkip_countermeasures) { 273 if (skb_headroom(skb) < 8 || skb->len < hdr_len)
275 if (net_ratelimit()) { 274 return NULL;
276 printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
277 "TX packet to " MAC_FMT "\n",
278 tkey->ieee->dev->name, MAC_ARG(hdr->addr1));
279 }
280 return -1;
281 }
282
283 if (skb_headroom(skb) < 8 || skb_tailroom(skb) < 4 ||
284 skb->len < hdr_len)
285 return -1;
286 275
287 if (!tkey->tx_phase1_done) { 276 if (!tkey->tx_phase1_done) {
288 tkip_mixing_phase1(tkey->tx_ttak, tkey->key, hdr->addr2, 277 tkip_mixing_phase1(tkey->tx_ttak, tkey->key, hdr->addr2,
289 tkey->tx_iv32); 278 tkey->tx_iv32);
290 tkey->tx_phase1_done = 1; 279 tkey->tx_phase1_done = 1;
291 } 280 }
281 rc4key = kmalloc(16, GFP_ATOMIC);
282 if (!rc4key)
283 return NULL;
292 tkip_mixing_phase2(rc4key, tkey->key, tkey->tx_ttak, tkey->tx_iv16); 284 tkip_mixing_phase2(rc4key, tkey->key, tkey->tx_ttak, tkey->tx_iv16);
293 285
294 len = skb->len - hdr_len; 286 len = skb->len - hdr_len;
@@ -297,9 +289,9 @@ static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
297 pos += hdr_len; 289 pos += hdr_len;
298 icv = skb_put(skb, 4); 290 icv = skb_put(skb, 4);
299 291
300 *pos++ = rc4key[0]; 292 *pos++ = *rc4key;
301 *pos++ = rc4key[1]; 293 *pos++ = *(rc4key + 1);
302 *pos++ = rc4key[2]; 294 *pos++ = *(rc4key + 2);
303 *pos++ = (tkey->key_idx << 6) | (1 << 5) /* Ext IV included */ ; 295 *pos++ = (tkey->key_idx << 6) | (1 << 5) /* Ext IV included */ ;
304 *pos++ = tkey->tx_iv32 & 0xff; 296 *pos++ = tkey->tx_iv32 & 0xff;
305 *pos++ = (tkey->tx_iv32 >> 8) & 0xff; 297 *pos++ = (tkey->tx_iv32 >> 8) & 0xff;
@@ -312,6 +304,38 @@ static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
312 icv[2] = crc >> 16; 304 icv[2] = crc >> 16;
313 icv[3] = crc >> 24; 305 icv[3] = crc >> 24;
314 306
307 return rc4key;
308}
309
310static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
311{
312 struct ieee80211_tkip_data *tkey = priv;
313 int len;
314 const u8 *rc4key;
315 u8 *pos;
316 struct scatterlist sg;
317
318 if (tkey->ieee->tkip_countermeasures) {
319 if (net_ratelimit()) {
320 struct ieee80211_hdr_4addr *hdr =
321 (struct ieee80211_hdr_4addr *)skb->data;
322 printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
323 "TX packet to " MAC_FMT "\n",
324 tkey->ieee->dev->name, MAC_ARG(hdr->addr1));
325 }
326 return -1;
327 }
328
329 if (skb_tailroom(skb) < 4 || skb->len < hdr_len)
330 return -1;
331
332 len = skb->len - hdr_len;
333 pos = skb->data + hdr_len;
334
335 rc4key = ieee80211_tkip_hdr(skb, hdr_len, priv);
336 if (!rc4key)
337 return -1;
338
315 crypto_cipher_setkey(tkey->tfm_arc4, rc4key, 16); 339 crypto_cipher_setkey(tkey->tfm_arc4, rc4key, 16);
316 sg.page = virt_to_page(pos); 340 sg.page = virt_to_page(pos);
317 sg.offset = offset_in_page(pos); 341 sg.offset = offset_in_page(pos);
diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c
index 256d5524445c..fcf05bf677b8 100644
--- a/net/ieee80211/ieee80211_rx.c
+++ b/net/ieee80211/ieee80211_rx.c
@@ -1534,6 +1534,12 @@ void ieee80211_rx_mgt(struct ieee80211_device *ieee,
1534 header); 1534 header);
1535 break; 1535 break;
1536 1536
1537 case IEEE80211_STYPE_DEAUTH:
1538 printk("DEAUTH from AP\n");
1539 if (ieee->handle_deauth != NULL)
1540 ieee->handle_deauth(ieee->dev, (struct ieee80211_auth *)
1541 header);
1542 break;
1537 default: 1543 default:
1538 IEEE80211_DEBUG_MGMT("received UNKNOWN (%d)\n", 1544 IEEE80211_DEBUG_MGMT("received UNKNOWN (%d)\n",
1539 WLAN_FC_GET_STYPE(le16_to_cpu 1545 WLAN_FC_GET_STYPE(le16_to_cpu
diff --git a/net/ieee80211/ieee80211_tx.c b/net/ieee80211/ieee80211_tx.c
index 24ade5f68e02..8d87897d7eb7 100644
--- a/net/ieee80211/ieee80211_tx.c
+++ b/net/ieee80211/ieee80211_tx.c
@@ -227,7 +227,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
227 rts_required; 227 rts_required;
228 unsigned long flags; 228 unsigned long flags;
229 struct net_device_stats *stats = &ieee->stats; 229 struct net_device_stats *stats = &ieee->stats;
230 int ether_type, encrypt, host_encrypt, host_encrypt_msdu; 230 int ether_type, encrypt, host_encrypt, host_encrypt_msdu, host_build_iv;
231 int bytes, fc, hdr_len; 231 int bytes, fc, hdr_len;
232 struct sk_buff *skb_frag; 232 struct sk_buff *skb_frag;
233 struct ieee80211_hdr_3addr header = { /* Ensure zero initialized */ 233 struct ieee80211_hdr_3addr header = { /* Ensure zero initialized */
@@ -263,8 +263,10 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
263 263
264 encrypt = !(ether_type == ETH_P_PAE && ieee->ieee802_1x) && 264 encrypt = !(ether_type == ETH_P_PAE && ieee->ieee802_1x) &&
265 ieee->sec.encrypt; 265 ieee->sec.encrypt;
266
266 host_encrypt = ieee->host_encrypt && encrypt; 267 host_encrypt = ieee->host_encrypt && encrypt;
267 host_encrypt_msdu = ieee->host_encrypt_msdu && encrypt; 268 host_encrypt_msdu = ieee->host_encrypt_msdu && encrypt;
269 host_build_iv = ieee->host_build_iv && encrypt;
268 270
269 if (!encrypt && ieee->ieee802_1x && 271 if (!encrypt && ieee->ieee802_1x &&
270 ieee->drop_unencrypted && ether_type != ETH_P_PAE) { 272 ieee->drop_unencrypted && ether_type != ETH_P_PAE) {
@@ -310,8 +312,10 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
310 int len = bytes + hdr_len + crypt->ops->extra_msdu_prefix_len + 312 int len = bytes + hdr_len + crypt->ops->extra_msdu_prefix_len +
311 crypt->ops->extra_msdu_postfix_len; 313 crypt->ops->extra_msdu_postfix_len;
312 struct sk_buff *skb_new = dev_alloc_skb(len); 314 struct sk_buff *skb_new = dev_alloc_skb(len);
315
313 if (unlikely(!skb_new)) 316 if (unlikely(!skb_new))
314 goto failed; 317 goto failed;
318
315 skb_reserve(skb_new, crypt->ops->extra_msdu_prefix_len); 319 skb_reserve(skb_new, crypt->ops->extra_msdu_prefix_len);
316 memcpy(skb_put(skb_new, hdr_len), &header, hdr_len); 320 memcpy(skb_put(skb_new, hdr_len), &header, hdr_len);
317 snapped = 1; 321 snapped = 1;
@@ -418,7 +422,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
418 for (; i < nr_frags; i++) { 422 for (; i < nr_frags; i++) {
419 skb_frag = txb->fragments[i]; 423 skb_frag = txb->fragments[i];
420 424
421 if (host_encrypt) 425 if (host_encrypt || host_build_iv)
422 skb_reserve(skb_frag, 426 skb_reserve(skb_frag,
423 crypt->ops->extra_mpdu_prefix_len); 427 crypt->ops->extra_mpdu_prefix_len);
424 428
@@ -453,6 +457,16 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
453 * to insert the IV between the header and the payload */ 457 * to insert the IV between the header and the payload */
454 if (host_encrypt) 458 if (host_encrypt)
455 ieee80211_encrypt_fragment(ieee, skb_frag, hdr_len); 459 ieee80211_encrypt_fragment(ieee, skb_frag, hdr_len);
460 else if (host_build_iv) {
461 struct ieee80211_crypt_data *crypt;
462
463 crypt = ieee->crypt[ieee->tx_keyidx];
464 atomic_inc(&crypt->refcnt);
465 if (crypt->ops->build_iv)
466 crypt->ops->build_iv(skb_frag, hdr_len,
467 crypt->priv);
468 atomic_dec(&crypt->refcnt);
469 }
456 470
457 if (ieee->config & 471 if (ieee->config &
458 (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS)) 472 (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS))