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:
parent
6cdd3979a2
commit
96fc6efb9a
@ -1697,6 +1697,7 @@ struct wireless_dev *ieee80211_vif_to_wdev(struct ieee80211_vif *vif);
|
|||||||
* @IEEE80211_KEY_FLAG_PUT_MIC_SPACE: This flag should be set by the driver for
|
* @IEEE80211_KEY_FLAG_PUT_MIC_SPACE: This flag should be set by the driver for
|
||||||
* a TKIP key if it only requires MIC space. Do not set together with
|
* a TKIP key if it only requires MIC space. Do not set together with
|
||||||
* @IEEE80211_KEY_FLAG_GENERATE_MMIC on the same key.
|
* @IEEE80211_KEY_FLAG_GENERATE_MMIC on the same key.
|
||||||
|
* @IEEE80211_KEY_FLAG_NO_AUTO_TX: Key needs explicit Tx activation.
|
||||||
*/
|
*/
|
||||||
enum ieee80211_key_flags {
|
enum ieee80211_key_flags {
|
||||||
IEEE80211_KEY_FLAG_GENERATE_IV_MGMT = BIT(0),
|
IEEE80211_KEY_FLAG_GENERATE_IV_MGMT = BIT(0),
|
||||||
@ -1708,6 +1709,7 @@ enum ieee80211_key_flags {
|
|||||||
IEEE80211_KEY_FLAG_RX_MGMT = BIT(6),
|
IEEE80211_KEY_FLAG_RX_MGMT = BIT(6),
|
||||||
IEEE80211_KEY_FLAG_RESERVE_TAILROOM = BIT(7),
|
IEEE80211_KEY_FLAG_RESERVE_TAILROOM = BIT(7),
|
||||||
IEEE80211_KEY_FLAG_PUT_MIC_SPACE = BIT(8),
|
IEEE80211_KEY_FLAG_PUT_MIC_SPACE = BIT(8),
|
||||||
|
IEEE80211_KEY_FLAG_NO_AUTO_TX = BIT(9),
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2243,6 +2245,9 @@ struct ieee80211_txq {
|
|||||||
* @IEEE80211_HW_SUPPORTS_ONLY_HE_MULTI_BSSID: Hardware supports multi BSSID
|
* @IEEE80211_HW_SUPPORTS_ONLY_HE_MULTI_BSSID: Hardware supports multi BSSID
|
||||||
* only for HE APs. Applies if @IEEE80211_HW_SUPPORTS_MULTI_BSSID is set.
|
* only for HE APs. Applies if @IEEE80211_HW_SUPPORTS_MULTI_BSSID is set.
|
||||||
*
|
*
|
||||||
|
* @IEEE80211_HW_EXT_KEY_ID_NATIVE: Driver and hardware are supporting Extended
|
||||||
|
* Key ID and can handle two unicast keys per station for Rx and Tx.
|
||||||
|
*
|
||||||
* @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays
|
* @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays
|
||||||
*/
|
*/
|
||||||
enum ieee80211_hw_flags {
|
enum ieee80211_hw_flags {
|
||||||
@ -2294,6 +2299,7 @@ enum ieee80211_hw_flags {
|
|||||||
IEEE80211_HW_TX_STATUS_NO_AMPDU_LEN,
|
IEEE80211_HW_TX_STATUS_NO_AMPDU_LEN,
|
||||||
IEEE80211_HW_SUPPORTS_MULTI_BSSID,
|
IEEE80211_HW_SUPPORTS_MULTI_BSSID,
|
||||||
IEEE80211_HW_SUPPORTS_ONLY_HE_MULTI_BSSID,
|
IEEE80211_HW_SUPPORTS_ONLY_HE_MULTI_BSSID,
|
||||||
|
IEEE80211_HW_EXT_KEY_ID_NATIVE,
|
||||||
|
|
||||||
/* keep last, obviously */
|
/* keep last, obviously */
|
||||||
NUM_IEEE80211_HW_FLAGS
|
NUM_IEEE80211_HW_FLAGS
|
||||||
|
@ -351,6 +351,36 @@ static int ieee80211_set_noack_map(struct wiphy *wiphy,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ieee80211_set_tx(struct ieee80211_sub_if_data *sdata,
|
||||||
|
const u8 *mac_addr, u8 key_idx)
|
||||||
|
{
|
||||||
|
struct ieee80211_local *local = sdata->local;
|
||||||
|
struct ieee80211_key *key;
|
||||||
|
struct sta_info *sta;
|
||||||
|
int ret = -EINVAL;
|
||||||
|
|
||||||
|
if (!wiphy_ext_feature_isset(local->hw.wiphy,
|
||||||
|
NL80211_EXT_FEATURE_EXT_KEY_ID))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
sta = sta_info_get_bss(sdata, mac_addr);
|
||||||
|
|
||||||
|
if (!sta)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (sta->ptk_idx == key_idx)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
mutex_lock(&local->key_mtx);
|
||||||
|
key = key_mtx_dereference(local, sta->ptk[key_idx]);
|
||||||
|
|
||||||
|
if (key && key->conf.flags & IEEE80211_KEY_FLAG_NO_AUTO_TX)
|
||||||
|
ret = ieee80211_set_tx_key(key);
|
||||||
|
|
||||||
|
mutex_unlock(&local->key_mtx);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
|
static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
|
||||||
u8 key_idx, bool pairwise, const u8 *mac_addr,
|
u8 key_idx, bool pairwise, const u8 *mac_addr,
|
||||||
struct key_params *params)
|
struct key_params *params)
|
||||||
@ -365,6 +395,9 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
|
|||||||
if (!ieee80211_sdata_running(sdata))
|
if (!ieee80211_sdata_running(sdata))
|
||||||
return -ENETDOWN;
|
return -ENETDOWN;
|
||||||
|
|
||||||
|
if (pairwise && params->mode == NL80211_KEY_SET_TX)
|
||||||
|
return ieee80211_set_tx(sdata, mac_addr, key_idx);
|
||||||
|
|
||||||
/* reject WEP and TKIP keys if WEP failed to initialize */
|
/* reject WEP and TKIP keys if WEP failed to initialize */
|
||||||
switch (params->cipher) {
|
switch (params->cipher) {
|
||||||
case WLAN_CIPHER_SUITE_WEP40:
|
case WLAN_CIPHER_SUITE_WEP40:
|
||||||
@ -396,6 +429,9 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
|
|||||||
if (pairwise)
|
if (pairwise)
|
||||||
key->conf.flags |= IEEE80211_KEY_FLAG_PAIRWISE;
|
key->conf.flags |= IEEE80211_KEY_FLAG_PAIRWISE;
|
||||||
|
|
||||||
|
if (params->mode == NL80211_KEY_NO_TX)
|
||||||
|
key->conf.flags |= IEEE80211_KEY_FLAG_NO_AUTO_TX;
|
||||||
|
|
||||||
mutex_lock(&local->sta_mtx);
|
mutex_lock(&local->sta_mtx);
|
||||||
|
|
||||||
if (mac_addr) {
|
if (mac_addr) {
|
||||||
|
@ -221,6 +221,7 @@ static const char *hw_flag_names[] = {
|
|||||||
FLAG(TX_STATUS_NO_AMPDU_LEN),
|
FLAG(TX_STATUS_NO_AMPDU_LEN),
|
||||||
FLAG(SUPPORTS_MULTI_BSSID),
|
FLAG(SUPPORTS_MULTI_BSSID),
|
||||||
FLAG(SUPPORTS_ONLY_HE_MULTI_BSSID),
|
FLAG(SUPPORTS_ONLY_HE_MULTI_BSSID),
|
||||||
|
FLAG(EXT_KEY_ID_NATIVE),
|
||||||
#undef FLAG
|
#undef FLAG
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1269,7 +1269,7 @@ struct ieee80211_local {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Key mutex, protects sdata's key_list and sta_info's
|
* Key mutex, protects sdata's key_list and sta_info's
|
||||||
* key pointers (write access, they're RCU.)
|
* key pointers and ptk_idx (write access, they're RCU.)
|
||||||
*/
|
*/
|
||||||
struct mutex key_mtx;
|
struct mutex key_mtx;
|
||||||
|
|
||||||
|
@ -265,9 +265,24 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
|
|||||||
sta ? sta->sta.addr : bcast_addr, ret);
|
sta ? sta->sta.addr : bcast_addr, ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ieee80211_set_tx_key(struct ieee80211_key *key)
|
||||||
|
{
|
||||||
|
struct sta_info *sta = key->sta;
|
||||||
|
struct ieee80211_local *local = key->local;
|
||||||
|
struct ieee80211_key *old;
|
||||||
|
|
||||||
|
assert_key_lock(local);
|
||||||
|
|
||||||
|
old = key_mtx_dereference(local, sta->ptk[sta->ptk_idx]);
|
||||||
|
sta->ptk_idx = key->conf.keyidx;
|
||||||
|
ieee80211_check_fast_xmit(sta);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int ieee80211_hw_key_replace(struct ieee80211_key *old_key,
|
static int ieee80211_hw_key_replace(struct ieee80211_key *old_key,
|
||||||
struct ieee80211_key *new_key,
|
struct ieee80211_key *new_key,
|
||||||
bool ptk0rekey)
|
bool pairwise)
|
||||||
{
|
{
|
||||||
struct ieee80211_sub_if_data *sdata;
|
struct ieee80211_sub_if_data *sdata;
|
||||||
struct ieee80211_local *local;
|
struct ieee80211_local *local;
|
||||||
@ -284,8 +299,9 @@ static int ieee80211_hw_key_replace(struct ieee80211_key *old_key,
|
|||||||
assert_key_lock(old_key->local);
|
assert_key_lock(old_key->local);
|
||||||
sta = old_key->sta;
|
sta = old_key->sta;
|
||||||
|
|
||||||
/* PTK only using key ID 0 needs special handling on rekey */
|
/* Unicast rekey without Extended Key ID needs special handling */
|
||||||
if (new_key && sta && ptk0rekey) {
|
if (new_key && sta && pairwise &&
|
||||||
|
rcu_access_pointer(sta->ptk[sta->ptk_idx]) == old_key) {
|
||||||
local = old_key->local;
|
local = old_key->local;
|
||||||
sdata = old_key->sdata;
|
sdata = old_key->sdata;
|
||||||
|
|
||||||
@ -401,10 +417,6 @@ static int ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
|
|||||||
|
|
||||||
if (old) {
|
if (old) {
|
||||||
idx = old->conf.keyidx;
|
idx = old->conf.keyidx;
|
||||||
/* TODO: proper implement and test "Extended Key ID for
|
|
||||||
* Individually Addressed Frames" from IEEE 802.11-2016.
|
|
||||||
* Till then always assume only key ID 0 is used for
|
|
||||||
* pairwise keys.*/
|
|
||||||
ret = ieee80211_hw_key_replace(old, new, pairwise);
|
ret = ieee80211_hw_key_replace(old, new, pairwise);
|
||||||
} else {
|
} else {
|
||||||
/* new must be provided in case old is not */
|
/* new must be provided in case old is not */
|
||||||
@ -421,15 +433,20 @@ static int ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
|
|||||||
if (sta) {
|
if (sta) {
|
||||||
if (pairwise) {
|
if (pairwise) {
|
||||||
rcu_assign_pointer(sta->ptk[idx], new);
|
rcu_assign_pointer(sta->ptk[idx], new);
|
||||||
sta->ptk_idx = idx;
|
if (new &&
|
||||||
if (new) {
|
!(new->conf.flags & IEEE80211_KEY_FLAG_NO_AUTO_TX)) {
|
||||||
|
sta->ptk_idx = idx;
|
||||||
clear_sta_flag(sta, WLAN_STA_BLOCK_BA);
|
clear_sta_flag(sta, WLAN_STA_BLOCK_BA);
|
||||||
ieee80211_check_fast_xmit(sta);
|
ieee80211_check_fast_xmit(sta);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
rcu_assign_pointer(sta->gtk[idx], new);
|
rcu_assign_pointer(sta->gtk[idx], new);
|
||||||
}
|
}
|
||||||
if (new)
|
/* Only needed for transition from no key -> key.
|
||||||
|
* Still triggers unnecessary when using Extended Key ID
|
||||||
|
* and installing the second key ID the first time.
|
||||||
|
*/
|
||||||
|
if (new && !old)
|
||||||
ieee80211_check_fast_rx(sta);
|
ieee80211_check_fast_rx(sta);
|
||||||
} else {
|
} else {
|
||||||
defunikey = old &&
|
defunikey = old &&
|
||||||
@ -745,16 +762,34 @@ int ieee80211_key_link(struct ieee80211_key *key,
|
|||||||
* can cause warnings to appear.
|
* can cause warnings to appear.
|
||||||
*/
|
*/
|
||||||
bool delay_tailroom = sdata->vif.type == NL80211_IFTYPE_STATION;
|
bool delay_tailroom = sdata->vif.type == NL80211_IFTYPE_STATION;
|
||||||
int ret;
|
int ret = -EOPNOTSUPP;
|
||||||
|
|
||||||
mutex_lock(&sdata->local->key_mtx);
|
mutex_lock(&sdata->local->key_mtx);
|
||||||
|
|
||||||
if (sta && pairwise)
|
if (sta && pairwise) {
|
||||||
|
struct ieee80211_key *alt_key;
|
||||||
|
|
||||||
old_key = key_mtx_dereference(sdata->local, sta->ptk[idx]);
|
old_key = key_mtx_dereference(sdata->local, sta->ptk[idx]);
|
||||||
else if (sta)
|
alt_key = key_mtx_dereference(sdata->local, sta->ptk[idx ^ 1]);
|
||||||
|
|
||||||
|
/* The rekey code assumes that the old and new key are using
|
||||||
|
* the same cipher. Enforce the assumption for pairwise keys.
|
||||||
|
*/
|
||||||
|
if (key &&
|
||||||
|
((alt_key && alt_key->conf.cipher != key->conf.cipher) ||
|
||||||
|
(old_key && old_key->conf.cipher != key->conf.cipher)))
|
||||||
|
goto out;
|
||||||
|
} else if (sta) {
|
||||||
old_key = key_mtx_dereference(sdata->local, sta->gtk[idx]);
|
old_key = key_mtx_dereference(sdata->local, sta->gtk[idx]);
|
||||||
else
|
} else {
|
||||||
old_key = key_mtx_dereference(sdata->local, sdata->keys[idx]);
|
old_key = key_mtx_dereference(sdata->local, sdata->keys[idx]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Non-pairwise keys must also not switch the cipher on rekey */
|
||||||
|
if (!pairwise) {
|
||||||
|
if (key && old_key && old_key->conf.cipher != key->conf.cipher)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Silently accept key re-installation without really installing the
|
* Silently accept key re-installation without really installing the
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
#define NUM_DEFAULT_KEYS 4
|
#define NUM_DEFAULT_KEYS 4
|
||||||
#define NUM_DEFAULT_MGMT_KEYS 2
|
#define NUM_DEFAULT_MGMT_KEYS 2
|
||||||
|
#define INVALID_PTK_KEYIDX 2 /* Keyidx always pointing to a NULL key for PTK */
|
||||||
|
|
||||||
struct ieee80211_local;
|
struct ieee80211_local;
|
||||||
struct ieee80211_sub_if_data;
|
struct ieee80211_sub_if_data;
|
||||||
@ -146,6 +147,7 @@ ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
|
|||||||
int ieee80211_key_link(struct ieee80211_key *key,
|
int ieee80211_key_link(struct ieee80211_key *key,
|
||||||
struct ieee80211_sub_if_data *sdata,
|
struct ieee80211_sub_if_data *sdata,
|
||||||
struct sta_info *sta);
|
struct sta_info *sta);
|
||||||
|
int ieee80211_set_tx_key(struct ieee80211_key *key);
|
||||||
void ieee80211_key_free(struct ieee80211_key *key, bool delay_tailroom);
|
void ieee80211_key_free(struct ieee80211_key *key, bool delay_tailroom);
|
||||||
void ieee80211_key_free_unused(struct ieee80211_key *key);
|
void ieee80211_key_free_unused(struct ieee80211_key *key);
|
||||||
void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx,
|
void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx,
|
||||||
|
@ -1051,6 +1051,11 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!local->ops->set_key ||
|
||||||
|
ieee80211_hw_check(&local->hw, EXT_KEY_ID_NATIVE))
|
||||||
|
wiphy_ext_feature_set(local->hw.wiphy,
|
||||||
|
NL80211_EXT_FEATURE_EXT_KEY_ID);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Calculate scan IE length -- we need this to alloc
|
* Calculate scan IE length -- we need this to alloc
|
||||||
* memory and to subtract from the driver limit. It
|
* memory and to subtract from the driver limit. It
|
||||||
|
@ -1005,23 +1005,43 @@ static int ieee80211_get_mmie_keyidx(struct sk_buff *skb)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ieee80211_get_cs_keyid(const struct ieee80211_cipher_scheme *cs,
|
static int ieee80211_get_keyid(struct sk_buff *skb,
|
||||||
struct sk_buff *skb)
|
const struct ieee80211_cipher_scheme *cs)
|
||||||
{
|
{
|
||||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||||
__le16 fc;
|
__le16 fc;
|
||||||
int hdrlen;
|
int hdrlen;
|
||||||
|
int minlen;
|
||||||
|
u8 key_idx_off;
|
||||||
|
u8 key_idx_shift;
|
||||||
u8 keyid;
|
u8 keyid;
|
||||||
|
|
||||||
fc = hdr->frame_control;
|
fc = hdr->frame_control;
|
||||||
hdrlen = ieee80211_hdrlen(fc);
|
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;
|
return -EINVAL;
|
||||||
|
|
||||||
skb_copy_bits(skb, hdrlen + cs->key_idx_off, &keyid, 1);
|
skb_copy_bits(skb, key_idx_off, &keyid, 1);
|
||||||
keyid &= cs->key_idx_mask;
|
|
||||||
keyid >>= cs->key_idx_shift;
|
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;
|
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_rx_status *status = IEEE80211_SKB_RXCB(skb);
|
||||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||||
int keyidx;
|
int keyidx;
|
||||||
int hdrlen;
|
|
||||||
ieee80211_rx_result result = RX_DROP_UNUSABLE;
|
ieee80211_rx_result result = RX_DROP_UNUSABLE;
|
||||||
struct ieee80211_key *sta_ptk = NULL;
|
struct ieee80211_key *sta_ptk = NULL;
|
||||||
|
struct ieee80211_key *ptk_idx = NULL;
|
||||||
int mmie_keyidx = -1;
|
int mmie_keyidx = -1;
|
||||||
__le16 fc;
|
__le16 fc;
|
||||||
const struct ieee80211_cipher_scheme *cs = NULL;
|
const struct ieee80211_cipher_scheme *cs = NULL;
|
||||||
@ -1892,21 +1912,24 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
|
|||||||
|
|
||||||
if (rx->sta) {
|
if (rx->sta) {
|
||||||
int keyid = rx->sta->ptk_idx;
|
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;
|
cs = rx->sta->cipher_scheme;
|
||||||
keyid = ieee80211_get_cs_keyid(cs, rx->skb);
|
keyid = ieee80211_get_keyid(rx->skb, cs);
|
||||||
|
|
||||||
if (unlikely(keyid < 0))
|
if (unlikely(keyid < 0))
|
||||||
return RX_DROP_UNUSABLE;
|
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))
|
if (!ieee80211_has_protected(fc))
|
||||||
mmie_keyidx = ieee80211_get_mmie_keyidx(rx->skb);
|
mmie_keyidx = ieee80211_get_mmie_keyidx(rx->skb);
|
||||||
|
|
||||||
if (!is_multicast_ether_addr(hdr->addr1) && sta_ptk) {
|
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) &&
|
if ((status->flag & RX_FLAG_DECRYPTED) &&
|
||||||
(status->flag & RX_FLAG_IV_STRIPPED))
|
(status->flag & RX_FLAG_IV_STRIPPED))
|
||||||
return RX_CONTINUE;
|
return RX_CONTINUE;
|
||||||
@ -1966,8 +1989,6 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
|
|||||||
}
|
}
|
||||||
return RX_CONTINUE;
|
return RX_CONTINUE;
|
||||||
} else {
|
} else {
|
||||||
u8 keyid;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The device doesn't give us the IV so we won't be
|
* The device doesn't give us the IV so we won't be
|
||||||
* able to look up the key. That's ok though, we
|
* 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))
|
(status->flag & RX_FLAG_IV_STRIPPED))
|
||||||
return RX_CONTINUE;
|
return RX_CONTINUE;
|
||||||
|
|
||||||
hdrlen = ieee80211_hdrlen(fc);
|
keyidx = ieee80211_get_keyid(rx->skb, cs);
|
||||||
|
|
||||||
if (cs) {
|
if (unlikely(keyidx < 0))
|
||||||
keyidx = ieee80211_get_cs_keyid(cs, rx->skb);
|
return RX_DROP_UNUSABLE;
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* check per-station GTK first, if multicast packet */
|
/* check per-station GTK first, if multicast packet */
|
||||||
if (is_multicast_ether_addr(hdr->addr1) && rx->sta)
|
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:
|
case WLAN_CIPHER_SUITE_GCMP_256:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* we also don't want to deal with WEP or cipher scheme
|
/* We also don't want to deal with
|
||||||
* since those require looking up the key idx in the
|
* WEP or cipher scheme.
|
||||||
* 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)
|
|
||||||
*/
|
*/
|
||||||
goto clear_rcu;
|
goto clear_rcu;
|
||||||
}
|
}
|
||||||
|
@ -347,6 +347,15 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
|
|||||||
sta->sta.max_rx_aggregation_subframes =
|
sta->sta.max_rx_aggregation_subframes =
|
||||||
local->hw.max_rx_aggregation_subframes;
|
local->hw.max_rx_aggregation_subframes;
|
||||||
|
|
||||||
|
/* Extended Key ID needs to install keys for keyid 0 and 1 Rx-only.
|
||||||
|
* The Tx path starts to use a key as soon as the key slot ptk_idx
|
||||||
|
* references to is not NULL. To not use the initial Rx-only key
|
||||||
|
* prematurely for Tx initialize ptk_idx to an impossible PTK keyid
|
||||||
|
* which always will refer to a NULL key.
|
||||||
|
*/
|
||||||
|
BUILD_BUG_ON(ARRAY_SIZE(sta->ptk) <= INVALID_PTK_KEYIDX);
|
||||||
|
sta->ptk_idx = INVALID_PTK_KEYIDX;
|
||||||
|
|
||||||
sta->local = local;
|
sta->local = local;
|
||||||
sta->sdata = sdata;
|
sta->sdata = sdata;
|
||||||
sta->rx_stats.last_rx = jiffies;
|
sta->rx_stats.last_rx = jiffies;
|
||||||
|
@ -3001,23 +3001,15 @@ void ieee80211_check_fast_xmit(struct sta_info *sta)
|
|||||||
switch (build.key->conf.cipher) {
|
switch (build.key->conf.cipher) {
|
||||||
case WLAN_CIPHER_SUITE_CCMP:
|
case WLAN_CIPHER_SUITE_CCMP:
|
||||||
case WLAN_CIPHER_SUITE_CCMP_256:
|
case WLAN_CIPHER_SUITE_CCMP_256:
|
||||||
/* add fixed key ID */
|
if (gen_iv)
|
||||||
if (gen_iv) {
|
|
||||||
(build.hdr + build.hdr_len)[3] =
|
|
||||||
0x20 | (build.key->conf.keyidx << 6);
|
|
||||||
build.pn_offs = build.hdr_len;
|
build.pn_offs = build.hdr_len;
|
||||||
}
|
|
||||||
if (gen_iv || iv_spc)
|
if (gen_iv || iv_spc)
|
||||||
build.hdr_len += IEEE80211_CCMP_HDR_LEN;
|
build.hdr_len += IEEE80211_CCMP_HDR_LEN;
|
||||||
break;
|
break;
|
||||||
case WLAN_CIPHER_SUITE_GCMP:
|
case WLAN_CIPHER_SUITE_GCMP:
|
||||||
case WLAN_CIPHER_SUITE_GCMP_256:
|
case WLAN_CIPHER_SUITE_GCMP_256:
|
||||||
/* add fixed key ID */
|
if (gen_iv)
|
||||||
if (gen_iv) {
|
|
||||||
(build.hdr + build.hdr_len)[3] =
|
|
||||||
0x20 | (build.key->conf.keyidx << 6);
|
|
||||||
build.pn_offs = build.hdr_len;
|
build.pn_offs = build.hdr_len;
|
||||||
}
|
|
||||||
if (gen_iv || iv_spc)
|
if (gen_iv || iv_spc)
|
||||||
build.hdr_len += IEEE80211_GCMP_HDR_LEN;
|
build.hdr_len += IEEE80211_GCMP_HDR_LEN;
|
||||||
break;
|
break;
|
||||||
@ -3388,6 +3380,7 @@ static void ieee80211_xmit_fast_finish(struct ieee80211_sub_if_data *sdata,
|
|||||||
pn = atomic64_inc_return(&key->conf.tx_pn);
|
pn = atomic64_inc_return(&key->conf.tx_pn);
|
||||||
crypto_hdr[0] = pn;
|
crypto_hdr[0] = pn;
|
||||||
crypto_hdr[1] = pn >> 8;
|
crypto_hdr[1] = pn >> 8;
|
||||||
|
crypto_hdr[3] = 0x20 | (key->conf.keyidx << 6);
|
||||||
crypto_hdr[4] = pn >> 16;
|
crypto_hdr[4] = pn >> 16;
|
||||||
crypto_hdr[5] = pn >> 24;
|
crypto_hdr[5] = pn >> 24;
|
||||||
crypto_hdr[6] = pn >> 32;
|
crypto_hdr[6] = pn >> 32;
|
||||||
|
Loading…
Reference in New Issue
Block a user