Commit e31b8213 authored by Johannes Berg's avatar Johannes Berg Committed by John W. Linville

cfg80211/mac80211: allow per-station GTKs

This adds API to allow adding per-station GTKs,
updates mac80211 to support it, and also allows
drivers to remove a key from hwaccel again when
this may be necessary due to multiple GTKs.
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 53f73c09
......@@ -161,7 +161,7 @@ static int iwm_key_init(struct iwm_key *key, u8 key_index,
}
static int iwm_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
u8 key_index, const u8 *mac_addr,
u8 key_index, bool pairwise, const u8 *mac_addr,
struct key_params *params)
{
struct iwm_priv *iwm = ndev_to_iwm(ndev);
......@@ -181,7 +181,8 @@ static int iwm_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
}
static int iwm_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
u8 key_index, const u8 *mac_addr, void *cookie,
u8 key_index, bool pairwise, const u8 *mac_addr,
void *cookie,
void (*callback)(void *cookie,
struct key_params*))
{
......@@ -206,7 +207,7 @@ static int iwm_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
static int iwm_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
u8 key_index, const u8 *mac_addr)
u8 key_index, bool pairwise, const u8 *mac_addr)
{
struct iwm_priv *iwm = ndev_to_iwm(ndev);
struct iwm_key *key = &iwm->keys[key_index];
......
......@@ -1438,7 +1438,7 @@ static int lbs_cfg_set_default_key(struct wiphy *wiphy,
static int lbs_cfg_add_key(struct wiphy *wiphy, struct net_device *netdev,
u8 idx, const u8 *mac_addr,
u8 idx, bool pairwise, const u8 *mac_addr,
struct key_params *params)
{
struct lbs_private *priv = wiphy_priv(wiphy);
......@@ -1498,7 +1498,7 @@ static int lbs_cfg_add_key(struct wiphy *wiphy, struct net_device *netdev,
static int lbs_cfg_del_key(struct wiphy *wiphy, struct net_device *netdev,
u8 key_index, const u8 *mac_addr)
u8 key_index, bool pairwise, const u8 *mac_addr)
{
lbs_deb_enter(LBS_DEB_CFG80211);
......
......@@ -540,11 +540,11 @@ static int rndis_set_channel(struct wiphy *wiphy, struct net_device *dev,
struct ieee80211_channel *chan, enum nl80211_channel_type channel_type);
static int rndis_add_key(struct wiphy *wiphy, struct net_device *netdev,
u8 key_index, const u8 *mac_addr,
struct key_params *params);
u8 key_index, bool pairwise, const u8 *mac_addr,
struct key_params *params);
static int rndis_del_key(struct wiphy *wiphy, struct net_device *netdev,
u8 key_index, const u8 *mac_addr);
u8 key_index, bool pairwise, const u8 *mac_addr);
static int rndis_set_default_key(struct wiphy *wiphy, struct net_device *netdev,
u8 key_index);
......@@ -2308,8 +2308,8 @@ static int rndis_set_channel(struct wiphy *wiphy, struct net_device *netdev,
}
static int rndis_add_key(struct wiphy *wiphy, struct net_device *netdev,
u8 key_index, const u8 *mac_addr,
struct key_params *params)
u8 key_index, bool pairwise, const u8 *mac_addr,
struct key_params *params)
{
struct rndis_wlan_private *priv = wiphy_priv(wiphy);
struct usbnet *usbdev = priv->usbdev;
......@@ -2344,7 +2344,7 @@ static int rndis_add_key(struct wiphy *wiphy, struct net_device *netdev,
}
static int rndis_del_key(struct wiphy *wiphy, struct net_device *netdev,
u8 key_index, const u8 *mac_addr)
u8 key_index, bool pairwise, const u8 *mac_addr)
{
struct rndis_wlan_private *priv = wiphy_priv(wiphy);
struct usbnet *usbdev = priv->usbdev;
......
......@@ -801,6 +801,9 @@ enum nl80211_commands {
* This is used in association with @NL80211_ATTR_WIPHY_TX_POWER_SETTING
* for non-automatic settings.
*
* @NL80211_ATTR_SUPPORT_IBSS_RSN: The device supports IBSS RSN, which mostly
* means support for per-station GTKs.
*
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
*/
......@@ -968,6 +971,8 @@ enum nl80211_attrs {
NL80211_ATTR_CONTROL_PORT_ETHERTYPE,
NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT,
NL80211_ATTR_SUPPORT_IBSS_RSN,
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
......@@ -1659,11 +1664,14 @@ enum nl80211_auth_type {
* @NL80211_KEYTYPE_GROUP: Group (broadcast/multicast) key
* @NL80211_KEYTYPE_PAIRWISE: Pairwise (unicast/individual) key
* @NL80211_KEYTYPE_PEERKEY: PeerKey (DLS)
* @NUM_NL80211_KEYTYPES: number of defined key types
*/
enum nl80211_key_type {
NL80211_KEYTYPE_GROUP,
NL80211_KEYTYPE_PAIRWISE,
NL80211_KEYTYPE_PEERKEY,
NUM_NL80211_KEYTYPES
};
/**
......@@ -1694,6 +1702,9 @@ enum nl80211_wpa_versions {
* CCMP keys, each six bytes in little endian
* @NL80211_KEY_DEFAULT: flag indicating default key
* @NL80211_KEY_DEFAULT_MGMT: flag indicating default management key
* @NL80211_KEY_TYPE: the key type from enum nl80211_key_type, if not
* specified the default depends on whether a MAC address was
* given with the command using the key or not (u32)
* @__NL80211_KEY_AFTER_LAST: internal
* @NL80211_KEY_MAX: highest key attribute
*/
......@@ -1705,6 +1716,7 @@ enum nl80211_key_attributes {
NL80211_KEY_SEQ,
NL80211_KEY_DEFAULT,
NL80211_KEY_DEFAULT_MGMT,
NL80211_KEY_TYPE,
/* keep last */
__NL80211_KEY_AFTER_LAST,
......
......@@ -1130,13 +1130,14 @@ struct cfg80211_ops {
struct vif_params *params);
int (*add_key)(struct wiphy *wiphy, struct net_device *netdev,
u8 key_index, const u8 *mac_addr,
u8 key_index, bool pairwise, const u8 *mac_addr,
struct key_params *params);
int (*get_key)(struct wiphy *wiphy, struct net_device *netdev,
u8 key_index, const u8 *mac_addr, void *cookie,
u8 key_index, bool pairwise, const u8 *mac_addr,
void *cookie,
void (*callback)(void *cookie, struct key_params*));
int (*del_key)(struct wiphy *wiphy, struct net_device *netdev,
u8 key_index, const u8 *mac_addr);
u8 key_index, bool pairwise, const u8 *mac_addr);
int (*set_default_key)(struct wiphy *wiphy,
struct net_device *netdev,
u8 key_index);
......@@ -1304,6 +1305,7 @@ struct cfg80211_ops {
* @WIPHY_FLAG_CONTROL_PORT_PROTOCOL: This device supports setting the
* control port protocol ethertype. The device also honours the
* control_port_no_encrypt flag.
* @WIPHY_FLAG_IBSS_RSN: The device supports IBSS RSN.
*/
enum wiphy_flags {
WIPHY_FLAG_CUSTOM_REGULATORY = BIT(0),
......@@ -1314,6 +1316,7 @@ enum wiphy_flags {
WIPHY_FLAG_4ADDR_AP = BIT(5),
WIPHY_FLAG_4ADDR_STATION = BIT(6),
WIPHY_FLAG_CONTROL_PORT_PROTOCOL = BIT(7),
WIPHY_FLAG_IBSS_RSN = BIT(7),
};
struct mac_address {
......
......@@ -1041,6 +1041,13 @@ enum ieee80211_tkip_key_type {
* @IEEE80211_HW_NEED_DTIM_PERIOD:
* This device needs to know the DTIM period for the BSS before
* associating.
*
* @IEEE80211_HW_SUPPORTS_PER_STA_GTK: The device's crypto engine supports
* per-station GTKs as used by IBSS RSN or during fast transition. If
* the device doesn't support per-station GTKs, but can be asked not
* to decrypt group addressed frames, then IBSS RSN support is still
* possible but software crypto will be used. Advertise the wiphy flag
* only in that case.
*/
enum ieee80211_hw_flags {
IEEE80211_HW_HAS_RATE_CONTROL = 1<<0,
......@@ -1064,6 +1071,7 @@ enum ieee80211_hw_flags {
IEEE80211_HW_REPORTS_TX_ACK_STATUS = 1<<18,
IEEE80211_HW_CONNECTION_MONITOR = 1<<19,
IEEE80211_HW_SUPPORTS_CQM_RSSI = 1<<20,
IEEE80211_HW_SUPPORTS_PER_STA_GTK = 1<<21,
};
/**
......@@ -2582,6 +2590,22 @@ void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success);
void ieee80211_request_smps(struct ieee80211_vif *vif,
enum ieee80211_smps_mode smps_mode);
/**
* ieee80211_key_removed - disable hw acceleration for key
* @key_conf: The key hw acceleration should be disabled for
*
* This allows drivers to indicate that the given key has been
* removed from hardware acceleration, due to a new key that
* was added. Don't use this if the key can continue to be used
* for TX, if the key restriction is on RX only it is permitted
* to keep the key for TX only and not call this function.
*
* Due to locking constraints, it may only be called during
* @set_key. This function must be allowed to sleep, and the
* key it tries to disable may still be used until it returns.
*/
void ieee80211_key_removed(struct ieee80211_key_conf *key_conf);
/* Rate control API */
/**
......
......@@ -103,7 +103,7 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
}
static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
u8 key_idx, const u8 *mac_addr,
u8 key_idx, bool pairwise, const u8 *mac_addr,
struct key_params *params)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
......@@ -131,6 +131,9 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
if (IS_ERR(key))
return PTR_ERR(key);
if (pairwise)
key->conf.flags |= IEEE80211_KEY_FLAG_PAIRWISE;
mutex_lock(&sdata->local->sta_mtx);
if (mac_addr) {
......@@ -153,7 +156,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
}
static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
u8 key_idx, const u8 *mac_addr)
u8 key_idx, bool pairwise, const u8 *mac_addr)
{
struct ieee80211_sub_if_data *sdata;
struct sta_info *sta;
......@@ -170,10 +173,17 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
if (!sta)
goto out_unlock;
if (sta->key) {
ieee80211_key_free(sdata->local, sta->key);
WARN_ON(sta->key);
ret = 0;
if (pairwise) {
if (sta->ptk) {
ieee80211_key_free(sdata->local, sta->ptk);
ret = 0;
}
} else {
if (sta->gtk[key_idx]) {
ieee80211_key_free(sdata->local,
sta->gtk[key_idx]);
ret = 0;
}
}
goto out_unlock;
......@@ -195,7 +205,8 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
}
static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
u8 key_idx, const u8 *mac_addr, void *cookie,
u8 key_idx, bool pairwise, const u8 *mac_addr,
void *cookie,
void (*callback)(void *cookie,
struct key_params *params))
{
......@@ -203,7 +214,7 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
struct sta_info *sta = NULL;
u8 seq[6] = {0};
struct key_params params;
struct ieee80211_key *key;
struct ieee80211_key *key = NULL;
u32 iv32;
u16 iv16;
int err = -ENOENT;
......@@ -217,7 +228,10 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
if (!sta)
goto out;
key = sta->key;
if (pairwise)
key = sta->ptk;
else if (key_idx < NUM_DEFAULT_KEYS)
key = sta->gtk[key_idx];
} else
key = sdata->keys[key_idx];
......
......@@ -549,8 +549,6 @@ struct ieee80211_sub_if_data {
struct ieee80211_fragment_entry fragments[IEEE80211_FRAGMENT_MAX];
unsigned int fragment_next;
#define NUM_DEFAULT_KEYS 4
#define NUM_DEFAULT_MGMT_KEYS 2
struct ieee80211_key *keys[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS];
struct ieee80211_key *default_key;
struct ieee80211_key *default_mgmt_key;
......
......@@ -68,15 +68,21 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
might_sleep();
if (!key->local->ops->set_key) {
ret = -EOPNOTSUPP;
if (!key->local->ops->set_key)
goto out_unsupported;
}
assert_key_lock(key->local);
sta = get_sta_for_key(key);
/*
* If this is a per-STA GTK, check if it
* is supported; if not, return.
*/
if (sta && !(key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE) &&
!(key->local->hw.flags & IEEE80211_HW_SUPPORTS_PER_STA_GTK))
goto out_unsupported;
sdata = key->sdata;
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
sdata = container_of(sdata->bss,
......@@ -85,31 +91,28 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
ret = drv_set_key(key->local, SET_KEY, sdata, sta, &key->conf);
if (!ret)
if (!ret) {
key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE;
return 0;
}
if (ret && ret != -ENOSPC && ret != -EOPNOTSUPP)
if (ret != -ENOSPC && ret != -EOPNOTSUPP)
wiphy_err(key->local->hw.wiphy,
"failed to set key (%d, %pM) to hardware (%d)\n",
key->conf.keyidx, sta ? sta->addr : bcast_addr, ret);
out_unsupported:
if (ret) {
switch (key->conf.cipher) {
case WLAN_CIPHER_SUITE_WEP40:
case WLAN_CIPHER_SUITE_WEP104:
case WLAN_CIPHER_SUITE_TKIP:
case WLAN_CIPHER_SUITE_CCMP:
case WLAN_CIPHER_SUITE_AES_CMAC:
/* all of these we can do in software */
ret = 0;
break;
default:
ret = -EINVAL;
}
out_unsupported:
switch (key->conf.cipher) {
case WLAN_CIPHER_SUITE_WEP40:
case WLAN_CIPHER_SUITE_WEP104:
case WLAN_CIPHER_SUITE_TKIP:
case WLAN_CIPHER_SUITE_CCMP:
case WLAN_CIPHER_SUITE_AES_CMAC:
/* all of these we can do in software */
return 0;
default:
return -EINVAL;
}
return ret;
}
static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
......@@ -147,6 +150,26 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
}
void ieee80211_key_removed(struct ieee80211_key_conf *key_conf)
{
struct ieee80211_key *key;
key = container_of(key_conf, struct ieee80211_key, conf);
might_sleep();
assert_key_lock(key->local);
key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
/*
* Flush TX path to avoid attempts to use this key
* after this function returns. Until then, drivers
* must be prepared to handle the key.
*/
synchronize_rcu();
}
EXPORT_SYMBOL_GPL(ieee80211_key_removed);
static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata,
int idx)
{
......@@ -202,6 +225,7 @@ void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata,
static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
struct sta_info *sta,
bool pairwise,
struct ieee80211_key *old,
struct ieee80211_key *new)
{
......@@ -210,8 +234,14 @@ static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
if (new)
list_add(&new->list, &sdata->key_list);
if (sta) {
rcu_assign_pointer(sta->key, new);
if (sta && pairwise) {
rcu_assign_pointer(sta->ptk, new);
} else if (sta) {
if (old)
idx = old->conf.keyidx;
else
idx = new->conf.keyidx;
rcu_assign_pointer(sta->gtk[idx], new);
} else {
WARN_ON(new && old && new->conf.keyidx != old->conf.keyidx);
......@@ -355,6 +385,7 @@ int ieee80211_key_link(struct ieee80211_key *key,
{
struct ieee80211_key *old_key;
int idx, ret;
bool pairwise = key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE;
BUG_ON(!sdata);
BUG_ON(!key);
......@@ -371,13 +402,6 @@ int ieee80211_key_link(struct ieee80211_key *key,
*/
if (test_sta_flags(sta, WLAN_STA_WME))
key->conf.flags |= IEEE80211_KEY_FLAG_WMM_STA;
/*
* This key is for a specific sta interface,
* inform the driver that it should try to store
* this key as pairwise key.
*/
key->conf.flags |= IEEE80211_KEY_FLAG_PAIRWISE;
} else {
if (sdata->vif.type == NL80211_IFTYPE_STATION) {
struct sta_info *ap;
......@@ -399,12 +423,14 @@ int ieee80211_key_link(struct ieee80211_key *key,
mutex_lock(&sdata->local->key_mtx);
if (sta)
old_key = sta->key;
if (sta && pairwise)
old_key = sta->ptk;
else if (sta)
old_key = sta->gtk[idx];
else
old_key = sdata->keys[idx];
__ieee80211_key_replace(sdata, sta, old_key, key);
__ieee80211_key_replace(sdata, sta, pairwise, old_key, key);
__ieee80211_key_destroy(old_key);
ieee80211_debugfs_key_add(key);
......@@ -423,7 +449,8 @@ static void __ieee80211_key_free(struct ieee80211_key *key)
*/
if (key->sdata)
__ieee80211_key_replace(key->sdata, key->sta,
key, NULL);
key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE,
key, NULL);
__ieee80211_key_destroy(key);
}
......
......@@ -16,6 +16,9 @@
#include <linux/rcupdate.h>
#include <net/mac80211.h>
#define NUM_DEFAULT_KEYS 4
#define NUM_DEFAULT_MGMT_KEYS 2
#define WEP_IV_LEN 4
#define WEP_ICV_LEN 4
#define ALG_TKIP_KEY_LEN 32
......
......@@ -846,7 +846,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
int keyidx;
int hdrlen;
ieee80211_rx_result result = RX_DROP_UNUSABLE;
struct ieee80211_key *stakey = NULL;
struct ieee80211_key *sta_ptk = NULL;
int mmie_keyidx = -1;
__le16 fc;
......@@ -888,15 +888,15 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
rx->key = NULL;
if (rx->sta)
stakey = rcu_dereference(rx->sta->key);
sta_ptk = rcu_dereference(rx->sta->ptk);
fc = hdr->frame_control;
if (!ieee80211_has_protected(fc))
mmie_keyidx = ieee80211_get_mmie_keyidx(rx->skb);
if (!is_multicast_ether_addr(hdr->addr1) && stakey) {
rx->key = stakey;
if (!is_multicast_ether_addr(hdr->addr1) && sta_ptk) {
rx->key = sta_ptk;
if ((status->flag & RX_FLAG_DECRYPTED) &&
(status->flag & RX_FLAG_IV_STRIPPED))
return RX_CONTINUE;
......@@ -912,7 +912,10 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
if (mmie_keyidx < NUM_DEFAULT_KEYS ||
mmie_keyidx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS)
return RX_DROP_MONITOR; /* unexpected BIP keyidx */
rx->key = rcu_dereference(rx->sdata->keys[mmie_keyidx]);
if (rx->sta)
rx->key = rcu_dereference(rx->sta->gtk[mmie_keyidx]);
if (!rx->key)
rx->key = rcu_dereference(rx->sdata->keys[mmie_keyidx]);
} else if (!ieee80211_has_protected(fc)) {
/*
* The frame was not protected, so skip decryption. However, we
......@@ -955,17 +958,25 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
skb_copy_bits(rx->skb, hdrlen + 3, &keyid, 1);
keyidx = keyid >> 6;
rx->key = rcu_dereference(rx->sdata->keys[keyidx]);
/* check per-station GTK first, if multicast packet */
if (is_multicast_ether_addr(hdr->addr1) && rx->sta)
rx->key = rcu_dereference(rx->sta->gtk[keyidx]);
/*
* RSNA-protected unicast frames should always be sent with
* pairwise or station-to-station keys, but for WEP we allow
* using a key index as well.
*/
if (rx->key && rx->key->conf.cipher != WLAN_CIPHER_SUITE_WEP40 &&
rx->key->conf.cipher != WLAN_CIPHER_SUITE_WEP104 &&
!is_multicast_ether_addr(hdr->addr1))
rx->key = NULL;
/* if not found, try default key */
if (!rx->key) {
rx->key = rcu_dereference(rx->sdata->keys[keyidx]);
/*
* RSNA-protected unicast frames should always be
* sent with pairwise or station-to-station keys,
* but for WEP we allow using a key index as well.
*/
if (rx->key &&
rx->key->conf.cipher != WLAN_CIPHER_SUITE_WEP40 &&
rx->key->conf.cipher != WLAN_CIPHER_SUITE_WEP104 &&
!is_multicast_ether_addr(hdr->addr1))
rx->key = NULL;
}
}
if (rx->key) {
......
......@@ -616,7 +616,7 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)
struct ieee80211_sub_if_data *sdata;
struct sk_buff *skb;
unsigned long flags;
int ret;
int ret, i;
might_sleep();
......@@ -644,10 +644,10 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)
if (ret)
return ret;
if (sta->key) {
ieee80211_key_free(local, sta->key);
WARN_ON(sta->key);
}
for (i = 0; i < NUM_DEFAULT_KEYS; i++)
ieee80211_key_free(local, sta->gtk[i]);
if (sta->ptk)
ieee80211_key_free(local, sta->ptk);
sta->dead = true;
......
......@@ -199,7 +199,8 @@ enum plink_state {
* @hnext: hash table linked list pointer
* @local: pointer to the global information
* @sdata: virtual interface this station belongs to
* @key: peer key negotiated with this station, if any
* @ptk: peer key negotiated with this station, if any
* @gtk: group keys negotiated with this station, if any
* @rate_ctrl: rate control algorithm reference
* @rate_ctrl_priv: rate control private per-STA pointer
* @last_tx_rate: rate used for last transmit, to report to userspace as
......@@ -254,7 +255,8 @@ struct sta_info {
struct sta_info *hnext;
struct ieee80211_local *local;
struct ieee80211_sub_if_data *sdata;
struct ieee80211_key *key;
struct ieee80211_key *gtk[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS];
struct ieee80211_key *ptk;
struct rate_control_ref *rate_ctrl;
void *rate_ctrl_priv;
spinlock_t lock;
......
......@@ -532,7 +532,7 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
if (unlikely(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT))
tx->key = NULL;
else if (tx->sta && (key = rcu_dereference(tx->sta->key)))
else if (tx->sta && (key = rcu_dereference(tx->sta->ptk)))
tx->key = key;
else if (ieee80211_is_mgmt(hdr->frame_control) &&
is_multicast_ether_addr(hdr->addr1) &&
......
......@@ -375,7 +375,7 @@ bool cfg80211_sme_failed_reassoc(struct wireless_dev *wdev);
/* internal helpers */
int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
struct key_params *params, int key_idx,
const u8 *mac_addr);
bool pairwise, const u8 *mac_addr);
void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
size_t ie_len, u16 reason, bool from_ap);
void cfg80211_sme_scan_done(struct net_device *dev);
......