mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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
					
				
					 10 changed files with 151 additions and 60 deletions
				
			
		| 
						 | 
				
			
			@ -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
 | 
			
		||||
 *	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_NO_AUTO_TX: Key needs explicit Tx activation.
 | 
			
		||||
 */
 | 
			
		||||
enum ieee80211_key_flags {
 | 
			
		||||
	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_RESERVE_TAILROOM	= BIT(7),
 | 
			
		||||
	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
 | 
			
		||||
 *	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
 | 
			
		||||
 */
 | 
			
		||||
enum ieee80211_hw_flags {
 | 
			
		||||
| 
						 | 
				
			
			@ -2294,6 +2299,7 @@ enum ieee80211_hw_flags {
 | 
			
		|||
	IEEE80211_HW_TX_STATUS_NO_AMPDU_LEN,
 | 
			
		||||
	IEEE80211_HW_SUPPORTS_MULTI_BSSID,
 | 
			
		||||
	IEEE80211_HW_SUPPORTS_ONLY_HE_MULTI_BSSID,
 | 
			
		||||
	IEEE80211_HW_EXT_KEY_ID_NATIVE,
 | 
			
		||||
 | 
			
		||||
	/* keep last, obviously */
 | 
			
		||||
	NUM_IEEE80211_HW_FLAGS
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -351,6 +351,36 @@ static int ieee80211_set_noack_map(struct wiphy *wiphy,
 | 
			
		|||
	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,
 | 
			
		||||
			     u8 key_idx, bool pairwise, const u8 *mac_addr,
 | 
			
		||||
			     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))
 | 
			
		||||
		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 */
 | 
			
		||||
	switch (params->cipher) {
 | 
			
		||||
	case WLAN_CIPHER_SUITE_WEP40:
 | 
			
		||||
| 
						 | 
				
			
			@ -396,6 +429,9 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
 | 
			
		|||
	if (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);
 | 
			
		||||
 | 
			
		||||
	if (mac_addr) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -221,6 +221,7 @@ static const char *hw_flag_names[] = {
 | 
			
		|||
	FLAG(TX_STATUS_NO_AMPDU_LEN),
 | 
			
		||||
	FLAG(SUPPORTS_MULTI_BSSID),
 | 
			
		||||
	FLAG(SUPPORTS_ONLY_HE_MULTI_BSSID),
 | 
			
		||||
	FLAG(EXT_KEY_ID_NATIVE),
 | 
			
		||||
#undef FLAG
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1269,7 +1269,7 @@ struct ieee80211_local {
 | 
			
		|||
 | 
			
		||||
	/*
 | 
			
		||||
	 * 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;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -265,9 +265,24 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
 | 
			
		|||
			  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,
 | 
			
		||||
				    struct ieee80211_key *new_key,
 | 
			
		||||
				    bool ptk0rekey)
 | 
			
		||||
				    bool pairwise)
 | 
			
		||||
{
 | 
			
		||||
	struct ieee80211_sub_if_data *sdata;
 | 
			
		||||
	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);
 | 
			
		||||
	sta = old_key->sta;
 | 
			
		||||
 | 
			
		||||
	/* PTK only using key ID 0 needs special handling on rekey */
 | 
			
		||||
	if (new_key && sta && ptk0rekey) {
 | 
			
		||||
	/* Unicast rekey without Extended Key ID needs special handling */
 | 
			
		||||
	if (new_key && sta && pairwise &&
 | 
			
		||||
	    rcu_access_pointer(sta->ptk[sta->ptk_idx]) == old_key) {
 | 
			
		||||
		local = old_key->local;
 | 
			
		||||
		sdata = old_key->sdata;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -401,10 +417,6 @@ static int ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
 | 
			
		|||
 | 
			
		||||
	if (old) {
 | 
			
		||||
		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);
 | 
			
		||||
	} else {
 | 
			
		||||
		/* 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 (pairwise) {
 | 
			
		||||
			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);
 | 
			
		||||
				ieee80211_check_fast_xmit(sta);
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			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);
 | 
			
		||||
	} else {
 | 
			
		||||
		defunikey = old &&
 | 
			
		||||
| 
						 | 
				
			
			@ -745,16 +762,34 @@ int ieee80211_key_link(struct ieee80211_key *key,
 | 
			
		|||
	 * can cause warnings to appear.
 | 
			
		||||
	 */
 | 
			
		||||
	bool delay_tailroom = sdata->vif.type == NL80211_IFTYPE_STATION;
 | 
			
		||||
	int ret;
 | 
			
		||||
	int ret = -EOPNOTSUPP;
 | 
			
		||||
 | 
			
		||||
	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]);
 | 
			
		||||
	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]);
 | 
			
		||||
	else
 | 
			
		||||
	} else {
 | 
			
		||||
		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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,6 +18,7 @@
 | 
			
		|||
 | 
			
		||||
#define NUM_DEFAULT_KEYS 4
 | 
			
		||||
#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_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,
 | 
			
		||||
		       struct ieee80211_sub_if_data *sdata,
 | 
			
		||||
		       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_unused(struct ieee80211_key *key);
 | 
			
		||||
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
 | 
			
		||||
	 * 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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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;
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -347,6 +347,15 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
 | 
			
		|||
	sta->sta.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->sdata = sdata;
 | 
			
		||||
	sta->rx_stats.last_rx = jiffies;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3001,23 +3001,15 @@ void ieee80211_check_fast_xmit(struct sta_info *sta)
 | 
			
		|||
		switch (build.key->conf.cipher) {
 | 
			
		||||
		case WLAN_CIPHER_SUITE_CCMP:
 | 
			
		||||
		case WLAN_CIPHER_SUITE_CCMP_256:
 | 
			
		||||
			/* add fixed key ID */
 | 
			
		||||
			if (gen_iv) {
 | 
			
		||||
				(build.hdr + build.hdr_len)[3] =
 | 
			
		||||
					0x20 | (build.key->conf.keyidx << 6);
 | 
			
		||||
			if (gen_iv)
 | 
			
		||||
				build.pn_offs = build.hdr_len;
 | 
			
		||||
			}
 | 
			
		||||
			if (gen_iv || iv_spc)
 | 
			
		||||
				build.hdr_len += IEEE80211_CCMP_HDR_LEN;
 | 
			
		||||
			break;
 | 
			
		||||
		case WLAN_CIPHER_SUITE_GCMP:
 | 
			
		||||
		case WLAN_CIPHER_SUITE_GCMP_256:
 | 
			
		||||
			/* add fixed key ID */
 | 
			
		||||
			if (gen_iv) {
 | 
			
		||||
				(build.hdr + build.hdr_len)[3] =
 | 
			
		||||
					0x20 | (build.key->conf.keyidx << 6);
 | 
			
		||||
			if (gen_iv)
 | 
			
		||||
				build.pn_offs = build.hdr_len;
 | 
			
		||||
			}
 | 
			
		||||
			if (gen_iv || iv_spc)
 | 
			
		||||
				build.hdr_len += IEEE80211_GCMP_HDR_LEN;
 | 
			
		||||
			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);
 | 
			
		||||
			crypto_hdr[0] = pn;
 | 
			
		||||
			crypto_hdr[1] = pn >> 8;
 | 
			
		||||
			crypto_hdr[3] = 0x20 | (key->conf.keyidx << 6);
 | 
			
		||||
			crypto_hdr[4] = pn >> 16;
 | 
			
		||||
			crypto_hdr[5] = pn >> 24;
 | 
			
		||||
			crypto_hdr[6] = pn >> 32;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue