diff options
-rw-r--r-- | include/net/ieee80211.h | 5 | ||||
-rw-r--r-- | include/net/ieee80211_crypt.h | 2 | ||||
-rw-r--r-- | net/ieee80211/ieee80211_crypt_ccmp.c | 41 | ||||
-rw-r--r-- | net/ieee80211/ieee80211_crypt_tkip.c | 60 | ||||
-rw-r--r-- | net/ieee80211/ieee80211_rx.c | 6 | ||||
-rw-r--r-- | net/ieee80211/ieee80211_tx.c | 18 |
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 | ||
810 | struct ieee80211_channel { | 810 | struct 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 | ||
194 | static int ieee80211_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv) | 194 | static 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 | |||
227 | static 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 | ||
263 | static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv) | 263 | static 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 | |||
310 | static 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)) |