mac80211: IEEE 802.11 Extended Key ID support
Add support for Extended Key ID as defined in IEEE 802.11-2016. - Implement the nl80211 API for Extended Key ID - Extend mac80211 API to allow drivers to support Extended Key ID - Enable Extended Key ID by default for drivers only supporting SW crypto (e.g. mac80211_hwsim) - Allow unicast Tx usage to be supressed (IEEE80211_KEY_FLAG_NO_AUTO_TX) - Select the decryption key based on the MPDU keyid - Enforce existing assumptions in the code that rekeys don't change the cipher Signed-off-by: Alexander Wetzel <alexander@wetzel-home.de> [remove module parameter] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
committed by
Johannes Berg
parent
6cdd3979a2
commit
96fc6efb9a
@ -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;
|
||||
}
|
||||
@ -1852,9 +1872,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;
|
||||
@ -1892,21 +1912,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;
|
||||
@ -1966,8 +1989,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
|
||||
@ -1981,23 +2002,10 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
|
||||
(status->flag & RX_FLAG_IV_STRIPPED))
|
||||
return RX_CONTINUE;
|
||||
|
||||
hdrlen = ieee80211_hdrlen(fc);
|
||||
keyidx = ieee80211_get_keyid(rx->skb, cs);
|
||||
|
||||
if (cs) {
|
||||
keyidx = ieee80211_get_cs_keyid(cs, rx->skb);
|
||||
|
||||
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)
|
||||
@ -4042,12 +4050,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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user