diff options
Diffstat (limited to 'net/ieee80211/ieee80211_rx.c')
-rw-r--r-- | net/ieee80211/ieee80211_rx.c | 68 |
1 files changed, 58 insertions, 10 deletions
diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c index 2759312a4204..d97e5412e31b 100644 --- a/net/ieee80211/ieee80211_rx.c +++ b/net/ieee80211/ieee80211_rx.c | |||
@@ -415,17 +415,16 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, | |||
415 | ieee->host_mc_decrypt : ieee->host_decrypt; | 415 | ieee->host_mc_decrypt : ieee->host_decrypt; |
416 | 416 | ||
417 | if (can_be_decrypted) { | 417 | if (can_be_decrypted) { |
418 | int idx = 0; | ||
419 | if (skb->len >= hdrlen + 3) { | 418 | if (skb->len >= hdrlen + 3) { |
420 | /* Top two-bits of byte 3 are the key index */ | 419 | /* Top two-bits of byte 3 are the key index */ |
421 | idx = skb->data[hdrlen + 3] >> 6; | 420 | keyidx = skb->data[hdrlen + 3] >> 6; |
422 | } | 421 | } |
423 | 422 | ||
424 | /* ieee->crypt[] is WEP_KEY (4) in length. Given that idx | 423 | /* ieee->crypt[] is WEP_KEY (4) in length. Given that keyidx |
425 | * is only allowed 2-bits of storage, no value of idx can | 424 | * is only allowed 2-bits of storage, no value of keyidx can |
426 | * be provided via above code that would result in idx | 425 | * be provided via above code that would result in keyidx |
427 | * being out of range */ | 426 | * being out of range */ |
428 | crypt = ieee->crypt[idx]; | 427 | crypt = ieee->crypt[keyidx]; |
429 | 428 | ||
430 | #ifdef NOT_YET | 429 | #ifdef NOT_YET |
431 | sta = NULL; | 430 | sta = NULL; |
@@ -479,6 +478,11 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, | |||
479 | goto rx_exit; | 478 | goto rx_exit; |
480 | } | 479 | } |
481 | #endif | 480 | #endif |
481 | /* drop duplicate 802.11 retransmissions (IEEE 802.11 Chap. 9.29) */ | ||
482 | if (sc == ieee->prev_seq_ctl) | ||
483 | goto rx_dropped; | ||
484 | else | ||
485 | ieee->prev_seq_ctl = sc; | ||
482 | 486 | ||
483 | /* Data frame - extract src/dst addresses */ | 487 | /* Data frame - extract src/dst addresses */ |
484 | if (skb->len < IEEE80211_3ADDR_LEN) | 488 | if (skb->len < IEEE80211_3ADDR_LEN) |
@@ -655,6 +659,51 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, | |||
655 | goto rx_dropped; | 659 | goto rx_dropped; |
656 | } | 660 | } |
657 | 661 | ||
662 | /* If the frame was decrypted in hardware, we may need to strip off | ||
663 | * any security data (IV, ICV, etc) that was left behind */ | ||
664 | if (!can_be_decrypted && (fc & IEEE80211_FCTL_PROTECTED) && | ||
665 | ieee->host_strip_iv_icv) { | ||
666 | int trimlen = 0; | ||
667 | |||
668 | /* Top two-bits of byte 3 are the key index */ | ||
669 | if (skb->len >= hdrlen + 3) | ||
670 | keyidx = skb->data[hdrlen + 3] >> 6; | ||
671 | |||
672 | /* To strip off any security data which appears before the | ||
673 | * payload, we simply increase hdrlen (as the header gets | ||
674 | * chopped off immediately below). For the security data which | ||
675 | * appears after the payload, we use skb_trim. */ | ||
676 | |||
677 | switch (ieee->sec.encode_alg[keyidx]) { | ||
678 | case SEC_ALG_WEP: | ||
679 | /* 4 byte IV */ | ||
680 | hdrlen += 4; | ||
681 | /* 4 byte ICV */ | ||
682 | trimlen = 4; | ||
683 | break; | ||
684 | case SEC_ALG_TKIP: | ||
685 | /* 4 byte IV, 4 byte ExtIV */ | ||
686 | hdrlen += 8; | ||
687 | /* 8 byte MIC, 4 byte ICV */ | ||
688 | trimlen = 12; | ||
689 | break; | ||
690 | case SEC_ALG_CCMP: | ||
691 | /* 8 byte CCMP header */ | ||
692 | hdrlen += 8; | ||
693 | /* 8 byte MIC */ | ||
694 | trimlen = 8; | ||
695 | break; | ||
696 | } | ||
697 | |||
698 | if (skb->len < trimlen) | ||
699 | goto rx_dropped; | ||
700 | |||
701 | __skb_trim(skb, skb->len - trimlen); | ||
702 | |||
703 | if (skb->len < hdrlen) | ||
704 | goto rx_dropped; | ||
705 | } | ||
706 | |||
658 | /* skb: hdr + (possible reassembled) full plaintext payload */ | 707 | /* skb: hdr + (possible reassembled) full plaintext payload */ |
659 | 708 | ||
660 | payload = skb->data + hdrlen; | 709 | payload = skb->data + hdrlen; |
@@ -1255,12 +1304,11 @@ static int ieee80211_parse_info_param(struct ieee80211_info_element | |||
1255 | case MFIE_TYPE_IBSS_DFS: | 1304 | case MFIE_TYPE_IBSS_DFS: |
1256 | if (network->ibss_dfs) | 1305 | if (network->ibss_dfs) |
1257 | break; | 1306 | break; |
1258 | network->ibss_dfs = | 1307 | network->ibss_dfs = kmemdup(info_element->data, |
1259 | kmalloc(info_element->len, GFP_ATOMIC); | 1308 | info_element->len, |
1309 | GFP_ATOMIC); | ||
1260 | if (!network->ibss_dfs) | 1310 | if (!network->ibss_dfs) |
1261 | return 1; | 1311 | return 1; |
1262 | memcpy(network->ibss_dfs, info_element->data, | ||
1263 | info_element->len); | ||
1264 | network->flags |= NETWORK_HAS_IBSS_DFS; | 1312 | network->flags |= NETWORK_HAS_IBSS_DFS; |
1265 | break; | 1313 | break; |
1266 | 1314 | ||