]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - net/mac80211/rx.c
Merge tag 'mac80211-next-for-davem-2019-04-26' of git://git.kernel.org/pub/scm/linux...
[linux.git] / net / mac80211 / rx.c
index bf0b187f994e9c56e191d2045f405cb6e6bac336..25577ede2986ec5616a94501145a9734ec402521 100644 (file)
@@ -1005,23 +1005,43 @@ static int ieee80211_get_mmie_keyidx(struct sk_buff *skb)
        return -1;
 }
 
-static int ieee80211_get_cs_keyid(const struct ieee80211_cipher_scheme *cs,
-                                 struct sk_buff *skb)
+static int ieee80211_get_keyid(struct sk_buff *skb,
+                              const struct ieee80211_cipher_scheme *cs)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
        __le16 fc;
        int hdrlen;
+       int minlen;
+       u8 key_idx_off;
+       u8 key_idx_shift;
        u8 keyid;
 
        fc = hdr->frame_control;
        hdrlen = ieee80211_hdrlen(fc);
 
-       if (skb->len < hdrlen + cs->hdr_len)
+       if (cs) {
+               minlen = hdrlen + cs->hdr_len;
+               key_idx_off = hdrlen + cs->key_idx_off;
+               key_idx_shift = cs->key_idx_shift;
+       } else {
+               /* WEP, TKIP, CCMP and GCMP */
+               minlen = hdrlen + IEEE80211_WEP_IV_LEN;
+               key_idx_off = hdrlen + 3;
+               key_idx_shift = 6;
+       }
+
+       if (unlikely(skb->len < minlen))
                return -EINVAL;
 
-       skb_copy_bits(skb, hdrlen + cs->key_idx_off, &keyid, 1);
-       keyid &= cs->key_idx_mask;
-       keyid >>= cs->key_idx_shift;
+       skb_copy_bits(skb, key_idx_off, &keyid, 1);
+
+       if (cs)
+               keyid &= cs->key_idx_mask;
+       keyid >>= key_idx_shift;
+
+       /* cs could use more than the usual two bits for the keyid */
+       if (unlikely(keyid >= NUM_DEFAULT_KEYS))
+               return -EINVAL;
 
        return keyid;
 }
@@ -1860,9 +1880,9 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
        struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
        int keyidx;
-       int hdrlen;
        ieee80211_rx_result result = RX_DROP_UNUSABLE;
        struct ieee80211_key *sta_ptk = NULL;
+       struct ieee80211_key *ptk_idx = NULL;
        int mmie_keyidx = -1;
        __le16 fc;
        const struct ieee80211_cipher_scheme *cs = NULL;
@@ -1900,21 +1920,24 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
 
        if (rx->sta) {
                int keyid = rx->sta->ptk_idx;
+               sta_ptk = rcu_dereference(rx->sta->ptk[keyid]);
 
-               if (ieee80211_has_protected(fc) && rx->sta->cipher_scheme) {
+               if (ieee80211_has_protected(fc)) {
                        cs = rx->sta->cipher_scheme;
-                       keyid = ieee80211_get_cs_keyid(cs, rx->skb);
+                       keyid = ieee80211_get_keyid(rx->skb, cs);
+
                        if (unlikely(keyid < 0))
                                return RX_DROP_UNUSABLE;
+
+                       ptk_idx = rcu_dereference(rx->sta->ptk[keyid]);
                }
-               sta_ptk = rcu_dereference(rx->sta->ptk[keyid]);
        }
 
        if (!ieee80211_has_protected(fc))
                mmie_keyidx = ieee80211_get_mmie_keyidx(rx->skb);
 
        if (!is_multicast_ether_addr(hdr->addr1) && sta_ptk) {
-               rx->key = sta_ptk;
+               rx->key = ptk_idx ? ptk_idx : sta_ptk;
                if ((status->flag & RX_FLAG_DECRYPTED) &&
                    (status->flag & RX_FLAG_IV_STRIPPED))
                        return RX_CONTINUE;
@@ -1974,8 +1997,6 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
                }
                return RX_CONTINUE;
        } else {
-               u8 keyid;
-
                /*
                 * The device doesn't give us the IV so we won't be
                 * able to look up the key. That's ok though, we
@@ -1989,23 +2010,10 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
                    (status->flag & RX_FLAG_IV_STRIPPED))
                        return RX_CONTINUE;
 
-               hdrlen = ieee80211_hdrlen(fc);
-
-               if (cs) {
-                       keyidx = ieee80211_get_cs_keyid(cs, rx->skb);
+               keyidx = ieee80211_get_keyid(rx->skb, cs);
 
-                       if (unlikely(keyidx < 0))
-                               return RX_DROP_UNUSABLE;
-               } else {
-                       if (rx->skb->len < 8 + hdrlen)
-                               return RX_DROP_UNUSABLE; /* TODO: count this? */
-                       /*
-                        * no need to call ieee80211_wep_get_keyidx,
-                        * it verifies a bunch of things we've done already
-                        */
-                       skb_copy_bits(rx->skb, hdrlen + 3, &keyid, 1);
-                       keyidx = keyid >> 6;
-               }
+               if (unlikely(keyidx < 0))
+                       return RX_DROP_UNUSABLE;
 
                /* check per-station GTK first, if multicast packet */
                if (is_multicast_ether_addr(hdr->addr1) && rx->sta)
@@ -4050,12 +4058,8 @@ void ieee80211_check_fast_rx(struct sta_info *sta)
                case WLAN_CIPHER_SUITE_GCMP_256:
                        break;
                default:
-                       /* we also don't want to deal with WEP or cipher scheme
-                        * since those require looking up the key idx in the
-                        * frame, rather than assuming the PTK is used
-                        * (we need to revisit this once we implement the real
-                        * PTK index, which is now valid in the spec, but we
-                        * haven't implemented that part yet)
+                       /* We also don't want to deal with
+                        * WEP or cipher scheme.
                         */
                        goto clear_rcu;
                }