diff options
Diffstat (limited to 'net/mac80211/wpa.c')
-rw-r--r-- | net/mac80211/wpa.c | 118 |
1 files changed, 117 insertions, 1 deletions
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index d65728220763..21448d629b15 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c | |||
@@ -127,7 +127,7 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx) | |||
127 | * APs with pairwise keys should never receive Michael MIC | 127 | * APs with pairwise keys should never receive Michael MIC |
128 | * errors for non-zero keyidx because these are reserved for | 128 | * errors for non-zero keyidx because these are reserved for |
129 | * group keys and only the AP is sending real multicast | 129 | * group keys and only the AP is sending real multicast |
130 | * frames in the BSS. ( | 130 | * frames in the BSS. |
131 | */ | 131 | */ |
132 | return RX_DROP_UNUSABLE; | 132 | return RX_DROP_UNUSABLE; |
133 | } | 133 | } |
@@ -545,6 +545,106 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx) | |||
545 | return RX_CONTINUE; | 545 | return RX_CONTINUE; |
546 | } | 546 | } |
547 | 547 | ||
548 | static ieee80211_tx_result | ||
549 | ieee80211_crypto_cs_encrypt(struct ieee80211_tx_data *tx, | ||
550 | struct sk_buff *skb) | ||
551 | { | ||
552 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | ||
553 | struct ieee80211_key *key = tx->key; | ||
554 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
555 | const struct ieee80211_cipher_scheme *cs = key->sta->cipher_scheme; | ||
556 | int hdrlen; | ||
557 | u8 *pos; | ||
558 | |||
559 | if (info->control.hw_key && | ||
560 | !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) { | ||
561 | /* hwaccel has no need for preallocated head room */ | ||
562 | return TX_CONTINUE; | ||
563 | } | ||
564 | |||
565 | if (unlikely(skb_headroom(skb) < cs->hdr_len && | ||
566 | pskb_expand_head(skb, cs->hdr_len, 0, GFP_ATOMIC))) | ||
567 | return TX_DROP; | ||
568 | |||
569 | hdrlen = ieee80211_hdrlen(hdr->frame_control); | ||
570 | |||
571 | pos = skb_push(skb, cs->hdr_len); | ||
572 | memmove(pos, pos + cs->hdr_len, hdrlen); | ||
573 | skb_set_network_header(skb, skb_network_offset(skb) + cs->hdr_len); | ||
574 | |||
575 | return TX_CONTINUE; | ||
576 | } | ||
577 | |||
578 | static inline int ieee80211_crypto_cs_pn_compare(u8 *pn1, u8 *pn2, int len) | ||
579 | { | ||
580 | int i; | ||
581 | |||
582 | /* pn is little endian */ | ||
583 | for (i = len - 1; i >= 0; i--) { | ||
584 | if (pn1[i] < pn2[i]) | ||
585 | return -1; | ||
586 | else if (pn1[i] > pn2[i]) | ||
587 | return 1; | ||
588 | } | ||
589 | |||
590 | return 0; | ||
591 | } | ||
592 | |||
593 | static ieee80211_rx_result | ||
594 | ieee80211_crypto_cs_decrypt(struct ieee80211_rx_data *rx) | ||
595 | { | ||
596 | struct ieee80211_key *key = rx->key; | ||
597 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; | ||
598 | const struct ieee80211_cipher_scheme *cs = NULL; | ||
599 | int hdrlen = ieee80211_hdrlen(hdr->frame_control); | ||
600 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); | ||
601 | int data_len; | ||
602 | u8 *rx_pn; | ||
603 | u8 *skb_pn; | ||
604 | u8 qos_tid; | ||
605 | |||
606 | if (!rx->sta || !rx->sta->cipher_scheme || | ||
607 | !(status->flag & RX_FLAG_DECRYPTED)) | ||
608 | return RX_DROP_UNUSABLE; | ||
609 | |||
610 | if (!ieee80211_is_data(hdr->frame_control)) | ||
611 | return RX_CONTINUE; | ||
612 | |||
613 | cs = rx->sta->cipher_scheme; | ||
614 | |||
615 | data_len = rx->skb->len - hdrlen - cs->hdr_len; | ||
616 | |||
617 | if (data_len < 0) | ||
618 | return RX_DROP_UNUSABLE; | ||
619 | |||
620 | if (ieee80211_is_data_qos(hdr->frame_control)) | ||
621 | qos_tid = *ieee80211_get_qos_ctl(hdr) & | ||
622 | IEEE80211_QOS_CTL_TID_MASK; | ||
623 | else | ||
624 | qos_tid = 0; | ||
625 | |||
626 | if (skb_linearize(rx->skb)) | ||
627 | return RX_DROP_UNUSABLE; | ||
628 | |||
629 | hdr = (struct ieee80211_hdr *)rx->skb->data; | ||
630 | |||
631 | rx_pn = key->u.gen.rx_pn[qos_tid]; | ||
632 | skb_pn = rx->skb->data + hdrlen + cs->pn_off; | ||
633 | |||
634 | if (ieee80211_crypto_cs_pn_compare(skb_pn, rx_pn, cs->pn_len) <= 0) | ||
635 | return RX_DROP_UNUSABLE; | ||
636 | |||
637 | memcpy(rx_pn, skb_pn, cs->pn_len); | ||
638 | |||
639 | /* remove security header and MIC */ | ||
640 | if (pskb_trim(rx->skb, rx->skb->len - cs->mic_len)) | ||
641 | return RX_DROP_UNUSABLE; | ||
642 | |||
643 | memmove(rx->skb->data + cs->hdr_len, rx->skb->data, hdrlen); | ||
644 | skb_pull(rx->skb, cs->hdr_len); | ||
645 | |||
646 | return RX_CONTINUE; | ||
647 | } | ||
548 | 648 | ||
549 | static void bip_aad(struct sk_buff *skb, u8 *aad) | 649 | static void bip_aad(struct sk_buff *skb, u8 *aad) |
550 | { | 650 | { |
@@ -685,6 +785,7 @@ ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx) | |||
685 | { | 785 | { |
686 | struct sk_buff *skb; | 786 | struct sk_buff *skb; |
687 | struct ieee80211_tx_info *info = NULL; | 787 | struct ieee80211_tx_info *info = NULL; |
788 | ieee80211_tx_result res; | ||
688 | 789 | ||
689 | skb_queue_walk(&tx->skbs, skb) { | 790 | skb_queue_walk(&tx->skbs, skb) { |
690 | info = IEEE80211_SKB_CB(skb); | 791 | info = IEEE80211_SKB_CB(skb); |
@@ -692,9 +793,24 @@ ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx) | |||
692 | /* handle hw-only algorithm */ | 793 | /* handle hw-only algorithm */ |
693 | if (!info->control.hw_key) | 794 | if (!info->control.hw_key) |
694 | return TX_DROP; | 795 | return TX_DROP; |
796 | |||
797 | if (tx->key->sta->cipher_scheme) { | ||
798 | res = ieee80211_crypto_cs_encrypt(tx, skb); | ||
799 | if (res != TX_CONTINUE) | ||
800 | return res; | ||
801 | } | ||
695 | } | 802 | } |
696 | 803 | ||
697 | ieee80211_tx_set_protected(tx); | 804 | ieee80211_tx_set_protected(tx); |
698 | 805 | ||
699 | return TX_CONTINUE; | 806 | return TX_CONTINUE; |
700 | } | 807 | } |
808 | |||
809 | ieee80211_rx_result | ||
810 | ieee80211_crypto_hw_decrypt(struct ieee80211_rx_data *rx) | ||
811 | { | ||
812 | if (rx->sta->cipher_scheme) | ||
813 | return ieee80211_crypto_cs_decrypt(rx); | ||
814 | |||
815 | return RX_DROP_UNUSABLE; | ||
816 | } | ||