aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/wpa.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/wpa.c')
-rw-r--r--net/mac80211/wpa.c116
1 files changed, 116 insertions, 0 deletions
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c
index d65728220763..7313d379c0d3 100644
--- a/net/mac80211/wpa.c
+++ b/net/mac80211/wpa.c
@@ -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
548static ieee80211_tx_result
549ieee80211_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
578static 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
593static ieee80211_rx_result
594ieee80211_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
549static void bip_aad(struct sk_buff *skb, u8 *aad) 649static 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
809ieee80211_rx_result
810ieee80211_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}