Commit 3b3e808c authored by David S. Miller's avatar David S. Miller

Merge tag 'mac80211-next-for-net-next-2020-02-24' of...

Merge tag 'mac80211-next-for-net-next-2020-02-24' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next

Johannes Berg says:

====================
A new set of changes:
 * lots of small documentation fixes, from Jérôme Pouiller
 * beacon protection (BIGTK) support from Jouni Malinen
 * some initial code for TID configuration, from Tamizh chelvam
 * I reverted some new API before it's actually used, because
   it's wrong to mix controlled port and preauth
 * a few other cleanups/fixes
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 13ef6ae8 370f51d5
...@@ -2947,6 +2947,7 @@ static int mac80211_hwsim_new_radio(struct genl_info *info, ...@@ -2947,6 +2947,7 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
NL80211_FEATURE_DYNAMIC_SMPS | NL80211_FEATURE_DYNAMIC_SMPS |
NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR; NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR;
wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_VHT_IBSS); wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_VHT_IBSS);
wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_BEACON_PROTECTION);
hw->wiphy->interface_modes = param->iftypes; hw->wiphy->interface_modes = param->iftypes;
......
This diff is collapsed.
...@@ -3776,6 +3776,9 @@ enum ieee80211_reconfig_type { ...@@ -3776,6 +3776,9 @@ enum ieee80211_reconfig_type {
* *
* @start_pmsr: start peer measurement (e.g. FTM) (this call can sleep) * @start_pmsr: start peer measurement (e.g. FTM) (this call can sleep)
* @abort_pmsr: abort peer measurement (this call can sleep) * @abort_pmsr: abort peer measurement (this call can sleep)
* @set_tid_config: Apply TID specific configurations. This callback may sleep.
* @reset_tid_config: Reset TID specific configuration for the peer.
* This callback may sleep.
*/ */
struct ieee80211_ops { struct ieee80211_ops {
void (*tx)(struct ieee80211_hw *hw, void (*tx)(struct ieee80211_hw *hw,
...@@ -4080,6 +4083,13 @@ struct ieee80211_ops { ...@@ -4080,6 +4083,13 @@ struct ieee80211_ops {
struct cfg80211_pmsr_request *request); struct cfg80211_pmsr_request *request);
void (*abort_pmsr)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, void (*abort_pmsr)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct cfg80211_pmsr_request *request); struct cfg80211_pmsr_request *request);
int (*set_tid_config)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct cfg80211_tid_config *tid_conf);
int (*reset_tid_config)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta, u8 tids);
}; };
/** /**
......
...@@ -264,6 +264,29 @@ ...@@ -264,6 +264,29 @@
* %NL80211_ATTR_VLAN_ID. * %NL80211_ATTR_VLAN_ID.
*/ */
/**
* DOC: TID configuration
*
* TID config support can be checked in the %NL80211_ATTR_TID_CONFIG
* attribute given in wiphy capabilities.
*
* The necessary configuration parameters are mentioned in
* &enum nl80211_tid_config_attr and it will be passed to the
* %NL80211_CMD_SET_TID_CONFIG command in %NL80211_ATTR_TID_CONFIG.
*
* If the configuration needs to be applied for specific peer then the MAC
* address of the peer needs to be passed in %NL80211_ATTR_MAC, otherwise the
* configuration will be applied for all the connected peers in the vif except
* any peers that have peer specific configuration for the TID by default; if
* the %NL80211_TID_CONFIG_ATTR_OVERRIDE flag is set, peer specific values
* will be overwritten.
*
* All this configuration is valid only for STA's current connection
* i.e. the configuration will be reset to default when the STA connects back
* after disconnection/roaming, and this configuration will be cleared when
* the interface goes down.
*/
/** /**
* enum nl80211_commands - supported nl80211 commands * enum nl80211_commands - supported nl80211 commands
* *
...@@ -1039,14 +1062,11 @@ ...@@ -1039,14 +1062,11 @@
* a control port frame and as a notification that a control port frame * a control port frame and as a notification that a control port frame
* has been received. %NL80211_ATTR_FRAME is used to specify the * has been received. %NL80211_ATTR_FRAME is used to specify the
* frame contents. The frame is the raw EAPoL data, without ethernet or * frame contents. The frame is the raw EAPoL data, without ethernet or
* 802.11 headers. An optional %NL80211_ATTR_SRC_MAC can be used to send * 802.11 headers.
* pre-auth frames to STAs on behalf of other APs.
* When used as an event indication %NL80211_ATTR_CONTROL_PORT_ETHERTYPE, * When used as an event indication %NL80211_ATTR_CONTROL_PORT_ETHERTYPE,
* %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT and %NL80211_ATTR_MAC are added * %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT and %NL80211_ATTR_MAC are added
* indicating the protocol type of the received frame; whether the frame * indicating the protocol type of the received frame; whether the frame
* was received unencrypted and the MAC address of the peer respectively. * was received unencrypted and the MAC address of the peer respectively.
* %NL80211_ATTR_DST_MAC can be used to forward pre-auth frames in
* userspace while using AP mode.
* *
* @NL80211_CMD_RELOAD_REGDB: Request that the regdb firmware file is reloaded. * @NL80211_CMD_RELOAD_REGDB: Request that the regdb firmware file is reloaded.
* *
...@@ -1128,6 +1148,9 @@ ...@@ -1128,6 +1148,9 @@
* peer MAC address and %NL80211_ATTR_FRAME is used to specify the frame * peer MAC address and %NL80211_ATTR_FRAME is used to specify the frame
* content. The frame is ethernet data. * content. The frame is ethernet data.
* *
* @NL80211_CMD_SET_TID_CONFIG: Data frame TID specific configuration
* is passed using %NL80211_ATTR_TID_CONFIG attribute.
*
* @NL80211_CMD_MAX: highest used command number * @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use * @__NL80211_CMD_AFTER_LAST: internal use
*/ */
...@@ -1352,6 +1375,8 @@ enum nl80211_commands { ...@@ -1352,6 +1375,8 @@ enum nl80211_commands {
NL80211_CMD_PROBE_MESH_LINK, NL80211_CMD_PROBE_MESH_LINK,
NL80211_CMD_SET_TID_CONFIG,
/* add new commands above here */ /* add new commands above here */
/* used to define NL80211_CMD_MAX below */ /* used to define NL80211_CMD_MAX below */
...@@ -2412,8 +2437,10 @@ enum nl80211_commands { ...@@ -2412,8 +2437,10 @@ enum nl80211_commands {
* %NL80211_ATTR_AKM_SUITES are default capabilities if AKM suites not * %NL80211_ATTR_AKM_SUITES are default capabilities if AKM suites not
* advertised for a specific interface type. * advertised for a specific interface type.
* *
* @NL80211_ATTR_SRC_MAC: MAC address used in control port over nl80211 transmit * @NL80211_ATTR_TID_CONFIG: TID specific configuration in a
* @NL80211_ATTR_DST_MAC: MAC address used in control port over nl80211 receive * nested attribute with &enum nl80211_tid_config_attr sub-attributes;
* on output (in wiphy attributes) it contains only the feature sub-
* attributes.
* *
* @NUM_NL80211_ATTR: total number of nl80211_attrs available * @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined * @NL80211_ATTR_MAX: highest attribute number currently defined
...@@ -2883,8 +2910,7 @@ enum nl80211_attrs { ...@@ -2883,8 +2910,7 @@ enum nl80211_attrs {
NL80211_ATTR_IFTYPE_AKM_SUITES, NL80211_ATTR_IFTYPE_AKM_SUITES,
NL80211_ATTR_SRC_MAC, NL80211_ATTR_TID_CONFIG,
NL80211_ATTR_DST_MAC,
/* add attributes here, update the policy in nl80211.c */ /* add attributes here, update the policy in nl80211.c */
...@@ -4559,6 +4585,7 @@ enum nl80211_key_default_types { ...@@ -4559,6 +4585,7 @@ enum nl80211_key_default_types {
* See &enum nl80211_key_default_types. * See &enum nl80211_key_default_types.
* @NL80211_KEY_MODE: the mode from enum nl80211_key_mode. * @NL80211_KEY_MODE: the mode from enum nl80211_key_mode.
* Defaults to @NL80211_KEY_RX_TX. * Defaults to @NL80211_KEY_RX_TX.
* @NL80211_KEY_DEFAULT_BEACON: flag indicating default Beacon frame key
* *
* @__NL80211_KEY_AFTER_LAST: internal * @__NL80211_KEY_AFTER_LAST: internal
* @NL80211_KEY_MAX: highest key attribute * @NL80211_KEY_MAX: highest key attribute
...@@ -4574,6 +4601,7 @@ enum nl80211_key_attributes { ...@@ -4574,6 +4601,7 @@ enum nl80211_key_attributes {
NL80211_KEY_TYPE, NL80211_KEY_TYPE,
NL80211_KEY_DEFAULT_TYPES, NL80211_KEY_DEFAULT_TYPES,
NL80211_KEY_MODE, NL80211_KEY_MODE,
NL80211_KEY_DEFAULT_BEACON,
/* keep last */ /* keep last */
__NL80211_KEY_AFTER_LAST, __NL80211_KEY_AFTER_LAST,
...@@ -4729,6 +4757,69 @@ enum nl80211_tx_power_setting { ...@@ -4729,6 +4757,69 @@ enum nl80211_tx_power_setting {
NL80211_TX_POWER_FIXED, NL80211_TX_POWER_FIXED,
}; };
/**
* enum nl80211_tid_config - TID config state
* @NL80211_TID_CONFIG_ENABLE: Enable config for the TID
* @NL80211_TID_CONFIG_DISABLE: Disable config for the TID
*/
enum nl80211_tid_config {
NL80211_TID_CONFIG_ENABLE,
NL80211_TID_CONFIG_DISABLE,
};
/* enum nl80211_tid_config_attr - TID specific configuration.
* @NL80211_TID_CONFIG_ATTR_PAD: pad attribute for 64-bit values
* @NL80211_TID_CONFIG_ATTR_VIF_SUPP: a bitmap (u64) of attributes supported
* for per-vif configuration; doesn't list the ones that are generic
* (%NL80211_TID_CONFIG_ATTR_TIDS, %NL80211_TID_CONFIG_ATTR_OVERRIDE).
* @NL80211_TID_CONFIG_ATTR_PEER_SUPP: same as the previous per-vif one, but
* per peer instead.
* @NL80211_TID_CONFIG_ATTR_OVERRIDE: flag attribue, if no peer
* is selected, if set indicates that the new configuration overrides
* all previous peer configurations, otherwise previous peer specific
* configurations should be left untouched. If peer is selected then
* it will reset particular TID configuration of that peer and it will
* not accept other TID config attributes along with peer.
* @NL80211_TID_CONFIG_ATTR_TIDS: a bitmask value of TIDs (bit 0 to 7)
* Its type is u16.
* @NL80211_TID_CONFIG_ATTR_NOACK: Configure ack policy for the TID.
* specified in %NL80211_TID_CONFIG_ATTR_TID. see %enum nl80211_tid_config.
* Its type is u8.
* @NL80211_TID_CONFIG_ATTR_RETRY_SHORT: Number of retries used with data frame
* transmission, user-space sets this configuration in
* &NL80211_CMD_SET_TID_CONFIG. It is u8 type, min value is 1 and
* the max value is advertised by the driver in this attribute on
* output in wiphy capabilities.
* @NL80211_TID_CONFIG_ATTR_RETRY_LONG: Number of retries used with data frame
* transmission, user-space sets this configuration in
* &NL80211_CMD_SET_TID_CONFIG. Its type is u8, min value is 1 and
* the max value is advertised by the driver in this attribute on
* output in wiphy capabilities.
* @NL80211_TID_CONFIG_ATTR_AMPDU_CTRL: Enable/Disable aggregation for the TIDs
* specified in %NL80211_TID_CONFIG_ATTR_TIDS. Its type is u8, using
* the values from &nl80211_tid_config.
* @NL80211_TID_CONFIG_ATTR_RTSCTS_CTRL: Enable/Disable RTS_CTS for the TIDs
* specified in %NL80211_TID_CONFIG_ATTR_TIDS. It is u8 type, using
* the values from &nl80211_tid_config.
*/
enum nl80211_tid_config_attr {
__NL80211_TID_CONFIG_ATTR_INVALID,
NL80211_TID_CONFIG_ATTR_PAD,
NL80211_TID_CONFIG_ATTR_VIF_SUPP,
NL80211_TID_CONFIG_ATTR_PEER_SUPP,
NL80211_TID_CONFIG_ATTR_OVERRIDE,
NL80211_TID_CONFIG_ATTR_TIDS,
NL80211_TID_CONFIG_ATTR_NOACK,
NL80211_TID_CONFIG_ATTR_RETRY_SHORT,
NL80211_TID_CONFIG_ATTR_RETRY_LONG,
NL80211_TID_CONFIG_ATTR_AMPDU_CTRL,
NL80211_TID_CONFIG_ATTR_RTSCTS_CTRL,
/* keep last */
__NL80211_TID_CONFIG_ATTR_AFTER_LAST,
NL80211_TID_CONFIG_ATTR_MAX = __NL80211_TID_CONFIG_ATTR_AFTER_LAST - 1
};
/** /**
* enum nl80211_packet_pattern_attr - packet pattern attribute * enum nl80211_packet_pattern_attr - packet pattern attribute
* @__NL80211_PKTPAT_INVALID: invalid number for nested attribute * @__NL80211_PKTPAT_INVALID: invalid number for nested attribute
...@@ -5548,9 +5639,8 @@ enum nl80211_feature_flags { ...@@ -5548,9 +5639,8 @@ enum nl80211_feature_flags {
* feature, which prevents bufferbloat by using the expected transmission * feature, which prevents bufferbloat by using the expected transmission
* time to limit the amount of data buffered in the hardware. * time to limit the amount of data buffered in the hardware.
* *
* @NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211_MAC_ADDRS: The driver * @NL80211_EXT_FEATURE_BEACON_PROTECTION: The driver supports Beacon protection
* can use src and dst MAC addresses with control port over nl80211 rx * and can receive key configuration for BIGTK using key indexes 6 and 7.
* and tx operations.
* *
* @NUM_NL80211_EXT_FEATURES: number of extended features. * @NUM_NL80211_EXT_FEATURES: number of extended features.
* @MAX_NL80211_EXT_FEATURES: highest extended feature index. * @MAX_NL80211_EXT_FEATURES: highest extended feature index.
...@@ -5599,7 +5689,7 @@ enum nl80211_ext_feature_index { ...@@ -5599,7 +5689,7 @@ enum nl80211_ext_feature_index {
NL80211_EXT_FEATURE_SAE_OFFLOAD, NL80211_EXT_FEATURE_SAE_OFFLOAD,
NL80211_EXT_FEATURE_VLAN_OFFLOAD, NL80211_EXT_FEATURE_VLAN_OFFLOAD,
NL80211_EXT_FEATURE_AQL, NL80211_EXT_FEATURE_AQL,
NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211_MAC_ADDRS, NL80211_EXT_FEATURE_BEACON_PROTECTION,
/* add new features before the definition below */ /* add new features before the definition below */
NUM_NL80211_EXT_FEATURES, NUM_NL80211_EXT_FEATURES,
......
...@@ -26,12 +26,20 @@ void ieee80211_aes_cmac(struct crypto_shash *tfm, const u8 *aad, ...@@ -26,12 +26,20 @@ void ieee80211_aes_cmac(struct crypto_shash *tfm, const u8 *aad,
{ {
SHASH_DESC_ON_STACK(desc, tfm); SHASH_DESC_ON_STACK(desc, tfm);
u8 out[AES_BLOCK_SIZE]; u8 out[AES_BLOCK_SIZE];
const __le16 *fc;
desc->tfm = tfm; desc->tfm = tfm;
crypto_shash_init(desc); crypto_shash_init(desc);
crypto_shash_update(desc, aad, AAD_LEN); crypto_shash_update(desc, aad, AAD_LEN);
crypto_shash_update(desc, data, data_len - CMAC_TLEN); fc = (const __le16 *)aad;
if (ieee80211_is_beacon(*fc)) {
/* mask Timestamp field to zero */
crypto_shash_update(desc, zero, 8);
crypto_shash_update(desc, data + 8, data_len - 8 - CMAC_TLEN);
} else {
crypto_shash_update(desc, data, data_len - CMAC_TLEN);
}
crypto_shash_finup(desc, zero, CMAC_TLEN, out); crypto_shash_finup(desc, zero, CMAC_TLEN, out);
memcpy(mic, out, CMAC_TLEN); memcpy(mic, out, CMAC_TLEN);
...@@ -41,12 +49,21 @@ void ieee80211_aes_cmac_256(struct crypto_shash *tfm, const u8 *aad, ...@@ -41,12 +49,21 @@ void ieee80211_aes_cmac_256(struct crypto_shash *tfm, const u8 *aad,
const u8 *data, size_t data_len, u8 *mic) const u8 *data, size_t data_len, u8 *mic)
{ {
SHASH_DESC_ON_STACK(desc, tfm); SHASH_DESC_ON_STACK(desc, tfm);
const __le16 *fc;
desc->tfm = tfm; desc->tfm = tfm;
crypto_shash_init(desc); crypto_shash_init(desc);
crypto_shash_update(desc, aad, AAD_LEN); crypto_shash_update(desc, aad, AAD_LEN);
crypto_shash_update(desc, data, data_len - CMAC_TLEN_256); fc = (const __le16 *)aad;
if (ieee80211_is_beacon(*fc)) {
/* mask Timestamp field to zero */
crypto_shash_update(desc, zero, 8);
crypto_shash_update(desc, data + 8,
data_len - 8 - CMAC_TLEN_256);
} else {
crypto_shash_update(desc, data, data_len - CMAC_TLEN_256);
}
crypto_shash_finup(desc, zero, CMAC_TLEN_256, mic); crypto_shash_finup(desc, zero, CMAC_TLEN_256, mic);
} }
......
...@@ -17,10 +17,11 @@ ...@@ -17,10 +17,11 @@
int ieee80211_aes_gmac(struct crypto_aead *tfm, const u8 *aad, u8 *nonce, int ieee80211_aes_gmac(struct crypto_aead *tfm, const u8 *aad, u8 *nonce,
const u8 *data, size_t data_len, u8 *mic) const u8 *data, size_t data_len, u8 *mic)
{ {
struct scatterlist sg[4]; struct scatterlist sg[5];
u8 *zero, *__aad, iv[AES_BLOCK_SIZE]; u8 *zero, *__aad, iv[AES_BLOCK_SIZE];
struct aead_request *aead_req; struct aead_request *aead_req;
int reqsize = sizeof(*aead_req) + crypto_aead_reqsize(tfm); int reqsize = sizeof(*aead_req) + crypto_aead_reqsize(tfm);
const __le16 *fc;
if (data_len < GMAC_MIC_LEN) if (data_len < GMAC_MIC_LEN)
return -EINVAL; return -EINVAL;
...@@ -33,11 +34,22 @@ int ieee80211_aes_gmac(struct crypto_aead *tfm, const u8 *aad, u8 *nonce, ...@@ -33,11 +34,22 @@ int ieee80211_aes_gmac(struct crypto_aead *tfm, const u8 *aad, u8 *nonce,
__aad = zero + GMAC_MIC_LEN; __aad = zero + GMAC_MIC_LEN;
memcpy(__aad, aad, GMAC_AAD_LEN); memcpy(__aad, aad, GMAC_AAD_LEN);
sg_init_table(sg, 4); fc = (const __le16 *)aad;
sg_set_buf(&sg[0], __aad, GMAC_AAD_LEN); if (ieee80211_is_beacon(*fc)) {
sg_set_buf(&sg[1], data, data_len - GMAC_MIC_LEN); /* mask Timestamp field to zero */
sg_set_buf(&sg[2], zero, GMAC_MIC_LEN); sg_init_table(sg, 5);
sg_set_buf(&sg[3], mic, GMAC_MIC_LEN); sg_set_buf(&sg[0], __aad, GMAC_AAD_LEN);
sg_set_buf(&sg[1], zero, 8);
sg_set_buf(&sg[2], data + 8, data_len - 8 - GMAC_MIC_LEN);
sg_set_buf(&sg[3], zero, GMAC_MIC_LEN);
sg_set_buf(&sg[4], mic, GMAC_MIC_LEN);
} else {
sg_init_table(sg, 4);
sg_set_buf(&sg[0], __aad, GMAC_AAD_LEN);
sg_set_buf(&sg[1], data, data_len - GMAC_MIC_LEN);
sg_set_buf(&sg[2], zero, GMAC_MIC_LEN);
sg_set_buf(&sg[3], mic, GMAC_MIC_LEN);
}
memcpy(iv, nonce, GMAC_NONCE_LEN); memcpy(iv, nonce, GMAC_NONCE_LEN);
memset(iv + GMAC_NONCE_LEN, 0, sizeof(iv) - GMAC_NONCE_LEN); memset(iv + GMAC_NONCE_LEN, 0, sizeof(iv) - GMAC_NONCE_LEN);
......
...@@ -568,7 +568,8 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, ...@@ -568,7 +568,8 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
if (pairwise && key_idx < NUM_DEFAULT_KEYS) if (pairwise && key_idx < NUM_DEFAULT_KEYS)
key = rcu_dereference(sta->ptk[key_idx]); key = rcu_dereference(sta->ptk[key_idx]);
else if (!pairwise && else if (!pairwise &&
key_idx < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS) key_idx < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS +
NUM_DEFAULT_BEACON_KEYS)
key = rcu_dereference(sta->gtk[key_idx]); key = rcu_dereference(sta->gtk[key_idx]);
} else } else
key = rcu_dereference(sdata->keys[key_idx]); key = rcu_dereference(sdata->keys[key_idx]);
...@@ -680,6 +681,17 @@ static int ieee80211_config_default_mgmt_key(struct wiphy *wiphy, ...@@ -680,6 +681,17 @@ static int ieee80211_config_default_mgmt_key(struct wiphy *wiphy,
return 0; return 0;
} }
static int ieee80211_config_default_beacon_key(struct wiphy *wiphy,
struct net_device *dev,
u8 key_idx)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
ieee80211_set_default_beacon_key(sdata, key_idx);
return 0;
}
void sta_set_rate_info_tx(struct sta_info *sta, void sta_set_rate_info_tx(struct sta_info *sta,
const struct ieee80211_tx_rate *rate, const struct ieee80211_tx_rate *rate,
struct rate_info *rinfo) struct rate_info *rinfo)
...@@ -3874,6 +3886,60 @@ ieee80211_abort_pmsr(struct wiphy *wiphy, struct wireless_dev *dev, ...@@ -3874,6 +3886,60 @@ ieee80211_abort_pmsr(struct wiphy *wiphy, struct wireless_dev *dev,
return drv_abort_pmsr(local, sdata, request); return drv_abort_pmsr(local, sdata, request);
} }
static int ieee80211_set_tid_config(struct wiphy *wiphy,
struct net_device *dev,
struct cfg80211_tid_config *tid_conf)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct sta_info *sta;
int ret;
if (!sdata->local->ops->set_tid_config)
return -EOPNOTSUPP;
if (!tid_conf->peer)
return drv_set_tid_config(sdata->local, sdata, NULL, tid_conf);
mutex_lock(&sdata->local->sta_mtx);
sta = sta_info_get_bss(sdata, tid_conf->peer);
if (!sta) {
mutex_unlock(&sdata->local->sta_mtx);
return -ENOENT;
}
ret = drv_set_tid_config(sdata->local, sdata, &sta->sta, tid_conf);
mutex_unlock(&sdata->local->sta_mtx);
return ret;
}
static int ieee80211_reset_tid_config(struct wiphy *wiphy,
struct net_device *dev,
const u8 *peer, u8 tid)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct sta_info *sta;
int ret;
if (!sdata->local->ops->reset_tid_config)
return -EOPNOTSUPP;
if (!peer)
return drv_reset_tid_config(sdata->local, sdata, NULL, tid);
mutex_lock(&sdata->local->sta_mtx);
sta = sta_info_get_bss(sdata, peer);
if (!sta) {
mutex_unlock(&sdata->local->sta_mtx);
return -ENOENT;
}
ret = drv_reset_tid_config(sdata->local, sdata, &sta->sta, tid);
mutex_unlock(&sdata->local->sta_mtx);
return ret;
}
const struct cfg80211_ops mac80211_config_ops = { const struct cfg80211_ops mac80211_config_ops = {
.add_virtual_intf = ieee80211_add_iface, .add_virtual_intf = ieee80211_add_iface,
.del_virtual_intf = ieee80211_del_iface, .del_virtual_intf = ieee80211_del_iface,
...@@ -3885,6 +3951,7 @@ const struct cfg80211_ops mac80211_config_ops = { ...@@ -3885,6 +3951,7 @@ const struct cfg80211_ops mac80211_config_ops = {
.get_key = ieee80211_get_key, .get_key = ieee80211_get_key,
.set_default_key = ieee80211_config_default_key, .set_default_key = ieee80211_config_default_key,
.set_default_mgmt_key = ieee80211_config_default_mgmt_key, .set_default_mgmt_key = ieee80211_config_default_mgmt_key,
.set_default_beacon_key = ieee80211_config_default_beacon_key,
.start_ap = ieee80211_start_ap, .start_ap = ieee80211_start_ap,
.change_beacon = ieee80211_change_beacon, .change_beacon = ieee80211_change_beacon,
.stop_ap = ieee80211_stop_ap, .stop_ap = ieee80211_stop_ap,
...@@ -3973,4 +4040,6 @@ const struct cfg80211_ops mac80211_config_ops = { ...@@ -3973,4 +4040,6 @@ const struct cfg80211_ops mac80211_config_ops = {
.start_pmsr = ieee80211_start_pmsr, .start_pmsr = ieee80211_start_pmsr,
.abort_pmsr = ieee80211_abort_pmsr, .abort_pmsr = ieee80211_abort_pmsr,
.probe_mesh_link = ieee80211_probe_mesh_link, .probe_mesh_link = ieee80211_probe_mesh_link,
.set_tid_config = ieee80211_set_tid_config,
.reset_tid_config = ieee80211_reset_tid_config,
}; };
...@@ -433,6 +433,37 @@ void ieee80211_debugfs_key_remove_mgmt_default(struct ieee80211_sub_if_data *sda ...@@ -433,6 +433,37 @@ void ieee80211_debugfs_key_remove_mgmt_default(struct ieee80211_sub_if_data *sda
sdata->debugfs.default_mgmt_key = NULL; sdata->debugfs.default_mgmt_key = NULL;
} }
void
ieee80211_debugfs_key_add_beacon_default(struct ieee80211_sub_if_data *sdata)
{
char buf[50];
struct ieee80211_key *key;
if (!sdata->vif.debugfs_dir)
return;
key = key_mtx_dereference(sdata->local,
sdata->default_beacon_key);
if (key) {
sprintf(buf, "../keys/%d", key->debugfs.cnt);
sdata->debugfs.default_beacon_key =
debugfs_create_symlink("default_beacon_key",
sdata->vif.debugfs_dir, buf);
} else {
ieee80211_debugfs_key_remove_beacon_default(sdata);
}
}
void
ieee80211_debugfs_key_remove_beacon_default(struct ieee80211_sub_if_data *sdata)
{
if (!sdata)
return;
debugfs_remove(sdata->debugfs.default_beacon_key);
sdata->debugfs.default_beacon_key = NULL;
}
void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key, void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key,
struct sta_info *sta) struct sta_info *sta)
{ {
......
...@@ -10,6 +10,10 @@ void ieee80211_debugfs_key_add_mgmt_default( ...@@ -10,6 +10,10 @@ void ieee80211_debugfs_key_add_mgmt_default(
struct ieee80211_sub_if_data *sdata); struct ieee80211_sub_if_data *sdata);
void ieee80211_debugfs_key_remove_mgmt_default( void ieee80211_debugfs_key_remove_mgmt_default(
struct ieee80211_sub_if_data *sdata); struct ieee80211_sub_if_data *sdata);
void ieee80211_debugfs_key_add_beacon_default(
struct ieee80211_sub_if_data *sdata);
void ieee80211_debugfs_key_remove_beacon_default(
struct ieee80211_sub_if_data *sdata);
void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key, void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key,
struct sta_info *sta); struct sta_info *sta);
#else #else
...@@ -26,6 +30,12 @@ static inline void ieee80211_debugfs_key_add_mgmt_default( ...@@ -26,6 +30,12 @@ static inline void ieee80211_debugfs_key_add_mgmt_default(
static inline void ieee80211_debugfs_key_remove_mgmt_default( static inline void ieee80211_debugfs_key_remove_mgmt_default(
struct ieee80211_sub_if_data *sdata) struct ieee80211_sub_if_data *sdata)
{} {}
static inline void ieee80211_debugfs_key_add_beacon_default(
struct ieee80211_sub_if_data *sdata)
{}
static inline void ieee80211_debugfs_key_remove_beacon_default(
struct ieee80211_sub_if_data *sdata)
{}
static inline void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key, static inline void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key,
struct sta_info *sta) struct sta_info *sta)
{} {}
......
...@@ -1358,4 +1358,31 @@ static inline void drv_del_nan_func(struct ieee80211_local *local, ...@@ -1358,4 +1358,31 @@ static inline void drv_del_nan_func(struct ieee80211_local *local,
trace_drv_return_void(local); trace_drv_return_void(local);
} }
static inline int drv_set_tid_config(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
struct ieee80211_sta *sta,
struct cfg80211_tid_config *tid_conf)
{
int ret;
might_sleep();
ret = local->ops->set_tid_config(&local->hw, &sdata->vif, sta,
tid_conf);
trace_drv_return_int(local, ret);
return ret;
}
static inline int drv_reset_tid_config(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
struct ieee80211_sta *sta, u8 tid)
{
int ret;
might_sleep();
ret = local->ops->reset_tid_config(&local->hw, &sdata->vif, sta, tid);
trace_drv_return_int(local, ret);
return ret;
}
#endif /* __MAC80211_DRIVER_OPS */ #endif /* __MAC80211_DRIVER_OPS */
...@@ -901,10 +901,13 @@ struct ieee80211_sub_if_data { ...@@ -901,10 +901,13 @@ struct ieee80211_sub_if_data {
/* bit field of ACM bits (BIT(802.1D tag)) */ /* bit field of ACM bits (BIT(802.1D tag)) */
u8 wmm_acm; u8 wmm_acm;
struct ieee80211_key __rcu *keys[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS]; struct ieee80211_key __rcu *keys[NUM_DEFAULT_KEYS +
NUM_DEFAULT_MGMT_KEYS +
NUM_DEFAULT_BEACON_KEYS];
struct ieee80211_key __rcu *default_unicast_key; struct ieee80211_key __rcu *default_unicast_key;
struct ieee80211_key __rcu *default_multicast_key; struct ieee80211_key __rcu *default_multicast_key;
struct ieee80211_key __rcu *default_mgmt_key; struct ieee80211_key __rcu *default_mgmt_key;
struct ieee80211_key __rcu *default_beacon_key;
u16 sequence_number; u16 sequence_number;
__be16 control_port_protocol; __be16 control_port_protocol;
...@@ -978,6 +981,7 @@ struct ieee80211_sub_if_data { ...@@ -978,6 +981,7 @@ struct ieee80211_sub_if_data {
struct dentry *default_unicast_key; struct dentry *default_unicast_key;
struct dentry *default_multicast_key; struct dentry *default_multicast_key;
struct dentry *default_mgmt_key; struct dentry *default_mgmt_key;
struct dentry *default_beacon_key;
} debugfs; } debugfs;
#endif #endif
...@@ -1792,8 +1796,7 @@ void ieee80211_check_fast_xmit_iface(struct ieee80211_sub_if_data *sdata); ...@@ -1792,8 +1796,7 @@ void ieee80211_check_fast_xmit_iface(struct ieee80211_sub_if_data *sdata);
void ieee80211_clear_fast_xmit(struct sta_info *sta); void ieee80211_clear_fast_xmit(struct sta_info *sta);
int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev, int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev,
const u8 *buf, size_t len, const u8 *buf, size_t len,
const u8 *dest, const u8 *src, __be16 proto, const u8 *dest, __be16 proto, bool unencrypted);
bool unencrypted);
int ieee80211_probe_mesh_link(struct wiphy *wiphy, struct net_device *dev, int ieee80211_probe_mesh_link(struct wiphy *wiphy, struct net_device *dev,
const u8 *buf, size_t len); const u8 *buf, size_t len);
......
...@@ -407,6 +407,31 @@ void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata, ...@@ -407,6 +407,31 @@ void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata,
mutex_unlock(&sdata->local->key_mtx); mutex_unlock(&sdata->local->key_mtx);
} }
static void
__ieee80211_set_default_beacon_key(struct ieee80211_sub_if_data *sdata, int idx)
{
struct ieee80211_key *key = NULL;
assert_key_lock(sdata->local);
if (idx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS &&
idx < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS +
NUM_DEFAULT_BEACON_KEYS)
key = key_mtx_dereference(sdata->local, sdata->keys[idx]);
rcu_assign_pointer(sdata->default_beacon_key, key);
ieee80211_debugfs_key_update_default(sdata);
}
void ieee80211_set_default_beacon_key(struct ieee80211_sub_if_data *sdata,
int idx)
{
mutex_lock(&sdata->local->key_mtx);
__ieee80211_set_default_beacon_key(sdata, idx);
mutex_unlock(&sdata->local->key_mtx);
}
static int ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, static int ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
struct sta_info *sta, struct sta_info *sta,
bool pairwise, bool pairwise,
...@@ -415,7 +440,7 @@ static int ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, ...@@ -415,7 +440,7 @@ static int ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
{ {
int idx; int idx;
int ret = 0; int ret = 0;
bool defunikey, defmultikey, defmgmtkey; bool defunikey, defmultikey, defmgmtkey, defbeaconkey;
/* caller must provide at least one old/new */ /* caller must provide at least one old/new */
if (WARN_ON(!new && !old)) if (WARN_ON(!new && !old))
...@@ -480,6 +505,9 @@ static int ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, ...@@ -480,6 +505,9 @@ static int ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
defmgmtkey = old && defmgmtkey = old &&
old == key_mtx_dereference(sdata->local, old == key_mtx_dereference(sdata->local,
sdata->default_mgmt_key); sdata->default_mgmt_key);
defbeaconkey = old &&
old == key_mtx_dereference(sdata->local,
sdata->default_beacon_key);
if (defunikey && !new) if (defunikey && !new)
__ieee80211_set_default_key(sdata, -1, true, false); __ieee80211_set_default_key(sdata, -1, true, false);
...@@ -487,6 +515,8 @@ static int ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, ...@@ -487,6 +515,8 @@ static int ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
__ieee80211_set_default_key(sdata, -1, false, true); __ieee80211_set_default_key(sdata, -1, false, true);
if (defmgmtkey && !new) if (defmgmtkey && !new)
__ieee80211_set_default_mgmt_key(sdata, -1); __ieee80211_set_default_mgmt_key(sdata, -1);
if (defbeaconkey && !new)
__ieee80211_set_default_beacon_key(sdata, -1);
rcu_assign_pointer(sdata->keys[idx], new); rcu_assign_pointer(sdata->keys[idx], new);
if (defunikey && new) if (defunikey && new)
...@@ -498,6 +528,9 @@ static int ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, ...@@ -498,6 +528,9 @@ static int ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
if (defmgmtkey && new) if (defmgmtkey && new)
__ieee80211_set_default_mgmt_key(sdata, __ieee80211_set_default_mgmt_key(sdata,
new->conf.keyidx); new->conf.keyidx);
if (defbeaconkey && new)
__ieee80211_set_default_beacon_key(sdata,
new->conf.keyidx);
} }
if (old) if (old)
...@@ -515,7 +548,9 @@ ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, ...@@ -515,7 +548,9 @@ ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
struct ieee80211_key *key; struct ieee80211_key *key;
int i, j, err; int i, j, err;
if (WARN_ON(idx < 0 || idx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS)) if (WARN_ON(idx < 0 ||
idx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS +
NUM_DEFAULT_BEACON_KEYS))
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
key = kzalloc(sizeof(struct ieee80211_key) + key_len, GFP_KERNEL); key = kzalloc(sizeof(struct ieee80211_key) + key_len, GFP_KERNEL);
...@@ -978,6 +1013,7 @@ static void ieee80211_free_keys_iface(struct ieee80211_sub_if_data *sdata, ...@@ -978,6 +1013,7 @@ static void ieee80211_free_keys_iface(struct ieee80211_sub_if_data *sdata,
sdata->crypto_tx_tailroom_pending_dec = 0; sdata->crypto_tx_tailroom_pending_dec = 0;
ieee80211_debugfs_key_remove_mgmt_default(sdata); ieee80211_debugfs_key_remove_mgmt_default(sdata);
ieee80211_debugfs_key_remove_beacon_default(sdata);
list_for_each_entry_safe(key, tmp, &sdata->key_list, list) { list_for_each_entry_safe(key, tmp, &sdata->key_list, list) {
ieee80211_key_replace(key->sdata, key->sta, ieee80211_key_replace(key->sdata, key->sta,
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#define NUM_DEFAULT_KEYS 4 #define NUM_DEFAULT_KEYS 4
#define NUM_DEFAULT_MGMT_KEYS 2 #define NUM_DEFAULT_MGMT_KEYS 2
#define NUM_DEFAULT_BEACON_KEYS 2
#define INVALID_PTK_KEYIDX 2 /* Keyidx always pointing to a NULL key for PTK */ #define INVALID_PTK_KEYIDX 2 /* Keyidx always pointing to a NULL key for PTK */
struct ieee80211_local; struct ieee80211_local;
...@@ -153,6 +154,8 @@ void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx, ...@@ -153,6 +154,8 @@ void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx,
bool uni, bool multi); bool uni, bool multi);
void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata, void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata,
int idx); int idx);
void ieee80211_set_default_beacon_key(struct ieee80211_sub_if_data *sdata,
int idx);
void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata, void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata,
bool force_synchronize); bool force_synchronize);
void ieee80211_free_sta_keys(struct ieee80211_local *local, void ieee80211_free_sta_keys(struct ieee80211_local *local,
......
...@@ -589,8 +589,6 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len, ...@@ -589,8 +589,6 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_FILS_STA); wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_FILS_STA);
wiphy_ext_feature_set(wiphy, wiphy_ext_feature_set(wiphy,
NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211); NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211);
wiphy_ext_feature_set(wiphy,
NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211_MAC_ADDRS);
if (!ops->hw_scan) { if (!ops->hw_scan) {
wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN | wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN |
......
...@@ -983,7 +983,8 @@ static int ieee80211_get_mmie_keyidx(struct sk_buff *skb) ...@@ -983,7 +983,8 @@ static int ieee80211_get_mmie_keyidx(struct sk_buff *skb)
if (skb->len < 24 + sizeof(*mmie) || !is_multicast_ether_addr(hdr->da)) if (skb->len < 24 + sizeof(*mmie) || !is_multicast_ether_addr(hdr->da))
return -1; return -1;
if (!ieee80211_is_robust_mgmt_frame(skb)) if (!ieee80211_is_robust_mgmt_frame(skb) &&
!ieee80211_is_beacon(hdr->frame_control))
return -1; /* not a robust management frame */ return -1; /* not a robust management frame */
mmie = (struct ieee80211_mmie *) mmie = (struct ieee80211_mmie *)
...@@ -1868,6 +1869,41 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) ...@@ -1868,6 +1869,41 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
return RX_CONTINUE; return RX_CONTINUE;
} /* ieee80211_rx_h_sta_process */ } /* ieee80211_rx_h_sta_process */
static struct ieee80211_key *
ieee80211_rx_get_bigtk(struct ieee80211_rx_data *rx, int idx)
{
struct ieee80211_key *key = NULL;
struct ieee80211_sub_if_data *sdata = rx->sdata;
int idx2;
/* Make sure key gets set if either BIGTK key index is set so that
* ieee80211_drop_unencrypted_mgmt() can properly drop both unprotected
* Beacon frames and Beacon frames that claim to use another BIGTK key
* index (i.e., a key that we do not have).
*/
if (idx < 0) {
idx = NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS;
idx2 = idx + 1;
} else {
if (idx == NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS)
idx2 = idx + 1;
else
idx2 = idx - 1;
}
if (rx->sta)
key = rcu_dereference(rx->sta->gtk[idx]);
if (!key)
key = rcu_dereference(sdata->keys[idx]);
if (!key && rx->sta)
key = rcu_dereference(rx->sta->gtk[idx2]);
if (!key)
key = rcu_dereference(sdata->keys[idx2]);
return key;
}
static ieee80211_rx_result debug_noinline static ieee80211_rx_result debug_noinline
ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
{ {
...@@ -1885,17 +1921,18 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) ...@@ -1885,17 +1921,18 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
/* /*
* Key selection 101 * Key selection 101
* *
* There are four types of keys: * There are five types of keys:
* - GTK (group keys) * - GTK (group keys)
* - IGTK (group keys for management frames) * - IGTK (group keys for management frames)
* - BIGTK (group keys for Beacon frames)
* - PTK (pairwise keys) * - PTK (pairwise keys)
* - STK (station-to-station pairwise keys) * - STK (station-to-station pairwise keys)
* *
* When selecting a key, we have to distinguish between multicast * When selecting a key, we have to distinguish between multicast
* (including broadcast) and unicast frames, the latter can only * (including broadcast) and unicast frames, the latter can only
* use PTKs and STKs while the former always use GTKs and IGTKs. * use PTKs and STKs while the former always use GTKs, IGTKs, and
* Unless, of course, actual WEP keys ("pre-RSNA") are used, then * BIGTKs. Unless, of course, actual WEP keys ("pre-RSNA") are used,
* unicast frames can also use key indices like GTKs. Hence, if we * then unicast frames can also use key indices like GTKs. Hence, if we
* don't have a PTK/STK we check the key index for a WEP key. * don't have a PTK/STK we check the key index for a WEP key.
* *
* Note that in a regular BSS, multicast frames are sent by the * Note that in a regular BSS, multicast frames are sent by the
...@@ -1939,6 +1976,20 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) ...@@ -1939,6 +1976,20 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
/* Skip decryption if the frame is not protected. */ /* Skip decryption if the frame is not protected. */
if (!ieee80211_has_protected(fc)) if (!ieee80211_has_protected(fc))
return RX_CONTINUE; return RX_CONTINUE;
} else if (mmie_keyidx >= 0 && ieee80211_is_beacon(fc)) {
/* Broadcast/multicast robust management frame / BIP */
if ((status->flag & RX_FLAG_DECRYPTED) &&
(status->flag & RX_FLAG_IV_STRIPPED))
return RX_CONTINUE;
if (mmie_keyidx < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS ||
mmie_keyidx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS +
NUM_DEFAULT_BEACON_KEYS)
return RX_DROP_MONITOR; /* unexpected BIP keyidx */
rx->key = ieee80211_rx_get_bigtk(rx, mmie_keyidx);
if (!rx->key)
return RX_CONTINUE; /* Beacon protection not in use */
} else if (mmie_keyidx >= 0) { } else if (mmie_keyidx >= 0) {
/* Broadcast/multicast robust management frame / BIP */ /* Broadcast/multicast robust management frame / BIP */
if ((status->flag & RX_FLAG_DECRYPTED) && if ((status->flag & RX_FLAG_DECRYPTED) &&
...@@ -1968,11 +2019,12 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) ...@@ -1968,11 +2019,12 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
struct ieee80211_sub_if_data *sdata = rx->sdata; struct ieee80211_sub_if_data *sdata = rx->sdata;
int i; int i;
if (ieee80211_is_mgmt(fc) && if (ieee80211_is_beacon(fc)) {
is_multicast_ether_addr(hdr->addr1) && key = ieee80211_rx_get_bigtk(rx, -1);
(key = rcu_dereference(rx->sdata->default_mgmt_key))) } else if (ieee80211_is_mgmt(fc) &&
rx->key = key; is_multicast_ether_addr(hdr->addr1)) {
else { key = rcu_dereference(rx->sdata->default_mgmt_key);
} else {
if (rx->sta) { if (rx->sta) {
for (i = 0; i < NUM_DEFAULT_KEYS; i++) { for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
key = rcu_dereference(rx->sta->gtk[i]); key = rcu_dereference(rx->sta->gtk[i]);
...@@ -1987,9 +2039,9 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) ...@@ -1987,9 +2039,9 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
break; break;
} }
} }
if (key)
rx->key = key;
} }
if (key)
rx->key = key;
return RX_CONTINUE; return RX_CONTINUE;
} else { } else {
/* /*
...@@ -2358,6 +2410,9 @@ static int ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx) ...@@ -2358,6 +2410,9 @@ static int ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx)
rx->skb->len); rx->skb->len);
return -EACCES; return -EACCES;
} }
if (unlikely(ieee80211_is_beacon(fc) && rx->key &&
ieee80211_get_mmie_keyidx(rx->skb) < 0))
return -EACCES;
/* /*
* When using MFP, Action frames are not allowed prior to * When using MFP, Action frames are not allowed prior to
* having configured keys. * having configured keys.
......
...@@ -201,8 +201,7 @@ ieee80211_bss_info_update(struct ieee80211_local *local, ...@@ -201,8 +201,7 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
mgmt->bssid, cbss->bssid); mgmt->bssid, cbss->bssid);
/* In case the signal is invalid update the status */ /* In case the signal is invalid update the status */
signal_valid = abs(channel->center_freq - cbss->channel->center_freq) signal_valid = channel == cbss->channel;
<= local->hw.wiphy->max_adj_channel_rssi_comp;
if (!signal_valid) if (!signal_valid)
rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL; rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL;
......
...@@ -533,7 +533,9 @@ struct sta_info { ...@@ -533,7 +533,9 @@ struct sta_info {
u8 addr[ETH_ALEN]; u8 addr[ETH_ALEN];
struct ieee80211_local *local; struct ieee80211_local *local;
struct ieee80211_sub_if_data *sdata; struct ieee80211_sub_if_data *sdata;
struct ieee80211_key __rcu *gtk[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS]; struct ieee80211_key __rcu *gtk[NUM_DEFAULT_KEYS +
NUM_DEFAULT_MGMT_KEYS +
NUM_DEFAULT_BEACON_KEYS];
struct ieee80211_key __rcu *ptk[NUM_DEFAULT_KEYS]; struct ieee80211_key __rcu *ptk[NUM_DEFAULT_KEYS];
u8 ptk_idx; u8 ptk_idx;
struct rate_control_ref *rate_ctrl; struct rate_control_ref *rate_ctrl;
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
* Copyright 2007 Johannes Berg <johannes@sipsolutions.net> * Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
* Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright 2013-2014 Intel Mobile Communications GmbH
* Copyright (C) 2018 Intel Corporation * Copyright (C) 2018-2020 Intel Corporation
* *
* Transmit and frame generation functions. * Transmit and frame generation functions.
*/ */
...@@ -3682,7 +3682,8 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw, ...@@ -3682,7 +3682,8 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
encap_out: encap_out:
IEEE80211_SKB_CB(skb)->control.vif = vif; IEEE80211_SKB_CB(skb)->control.vif = vif;
if (wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL)) { if (vif &&
wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL)) {
u32 airtime; u32 airtime;
airtime = ieee80211_calc_expected_tx_airtime(hw, vif, txq->sta, airtime = ieee80211_calc_expected_tx_airtime(hw, vif, txq->sta,
...@@ -4663,6 +4664,28 @@ bool ieee80211_csa_is_complete(struct ieee80211_vif *vif) ...@@ -4663,6 +4664,28 @@ bool ieee80211_csa_is_complete(struct ieee80211_vif *vif)
} }
EXPORT_SYMBOL(ieee80211_csa_is_complete); EXPORT_SYMBOL(ieee80211_csa_is_complete);
static int ieee80211_beacon_protect(struct sk_buff *skb,
struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata)
{
ieee80211_tx_result res;
struct ieee80211_tx_data tx;
memset(&tx, 0, sizeof(tx));
tx.key = rcu_dereference(sdata->default_beacon_key);
if (!tx.key)
return 0;
tx.local = local;
tx.sdata = sdata;
__skb_queue_head_init(&tx.skbs);
__skb_queue_tail(&tx.skbs, skb);
res = ieee80211_tx_h_encrypt(&tx);
if (WARN_ON_ONCE(res != TX_CONTINUE))
return -1;
return 0;
}
static struct sk_buff * static struct sk_buff *
__ieee80211_beacon_get(struct ieee80211_hw *hw, __ieee80211_beacon_get(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
...@@ -4730,6 +4753,9 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, ...@@ -4730,6 +4753,9 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw,
if (beacon->tail) if (beacon->tail)
skb_put_data(skb, beacon->tail, skb_put_data(skb, beacon->tail,
beacon->tail_len); beacon->tail_len);
if (ieee80211_beacon_protect(skb, local, sdata) < 0)
goto out;
} else } else
goto out; goto out;
} else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
...@@ -5282,8 +5308,7 @@ void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, ...@@ -5282,8 +5308,7 @@ void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata,
int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev, int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev,
const u8 *buf, size_t len, const u8 *buf, size_t len,
const u8 *dest, const u8 *src, __be16 proto, const u8 *dest, __be16 proto, bool unencrypted)
bool unencrypted)
{ {
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_local *local = sdata->local; struct ieee80211_local *local = sdata->local;
...@@ -5314,7 +5339,7 @@ int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev, ...@@ -5314,7 +5339,7 @@ int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev,
ehdr = skb_push(skb, sizeof(struct ethhdr)); ehdr = skb_push(skb, sizeof(struct ethhdr));
memcpy(ehdr->h_dest, dest, ETH_ALEN); memcpy(ehdr->h_dest, dest, ETH_ALEN);
memcpy(ehdr->h_source, src, ETH_ALEN); memcpy(ehdr->h_source, sdata->vif.addr, ETH_ALEN);
ehdr->h_proto = proto; ehdr->h_proto = proto;
skb->dev = dev; skb->dev = dev;
......
This diff is collapsed.
...@@ -136,6 +136,19 @@ rdev_set_default_mgmt_key(struct cfg80211_registered_device *rdev, ...@@ -136,6 +136,19 @@ rdev_set_default_mgmt_key(struct cfg80211_registered_device *rdev,
return ret; return ret;
} }
static inline int
rdev_set_default_beacon_key(struct cfg80211_registered_device *rdev,
struct net_device *netdev, u8 key_index)
{
int ret;
trace_rdev_set_default_beacon_key(&rdev->wiphy, netdev, key_index);
ret = rdev->ops->set_default_beacon_key(&rdev->wiphy, netdev,
key_index);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int rdev_start_ap(struct cfg80211_registered_device *rdev, static inline int rdev_start_ap(struct cfg80211_registered_device *rdev,
struct net_device *dev, struct net_device *dev,
struct cfg80211_ap_settings *settings) struct cfg80211_ap_settings *settings)
...@@ -734,14 +747,14 @@ static inline int rdev_mgmt_tx(struct cfg80211_registered_device *rdev, ...@@ -734,14 +747,14 @@ static inline int rdev_mgmt_tx(struct cfg80211_registered_device *rdev,
static inline int rdev_tx_control_port(struct cfg80211_registered_device *rdev, static inline int rdev_tx_control_port(struct cfg80211_registered_device *rdev,
struct net_device *dev, struct net_device *dev,
const void *buf, size_t len, const void *buf, size_t len,
const u8 *dest, const u8 *src, const u8 *dest, __be16 proto,
__be16 proto, const bool noencrypt) const bool noencrypt)
{ {
int ret; int ret;
trace_rdev_tx_control_port(&rdev->wiphy, dev, buf, len, trace_rdev_tx_control_port(&rdev->wiphy, dev, buf, len,
dest, src, proto, noencrypt); dest, proto, noencrypt);
ret = rdev->ops->tx_control_port(&rdev->wiphy, dev, buf, len, ret = rdev->ops->tx_control_port(&rdev->wiphy, dev, buf, len,
dest, src, proto, noencrypt); dest, proto, noencrypt);
trace_rdev_return_int(&rdev->wiphy, ret); trace_rdev_return_int(&rdev->wiphy, ret);
return ret; return ret;
} }
...@@ -1313,4 +1326,28 @@ rdev_probe_mesh_link(struct cfg80211_registered_device *rdev, ...@@ -1313,4 +1326,28 @@ rdev_probe_mesh_link(struct cfg80211_registered_device *rdev,
return ret; return ret;
} }
static inline int rdev_set_tid_config(struct cfg80211_registered_device *rdev,
struct net_device *dev,
struct cfg80211_tid_config *tid_conf)
{
int ret;
trace_rdev_set_tid_config(&rdev->wiphy, dev, tid_conf);
ret = rdev->ops->set_tid_config(&rdev->wiphy, dev, tid_conf);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int rdev_reset_tid_config(struct cfg80211_registered_device *rdev,
struct net_device *dev, const u8 *peer,
u8 tids)
{
int ret;
trace_rdev_reset_tid_config(&rdev->wiphy, dev, peer, tids);
ret = rdev->ops->reset_tid_config(&rdev->wiphy, dev, peer, tids);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
#endif /* __CFG80211_RDEV_OPS */ #endif /* __CFG80211_RDEV_OPS */
...@@ -556,9 +556,8 @@ cfg80211_find_sched_scan_req(struct cfg80211_registered_device *rdev, u64 reqid) ...@@ -556,9 +556,8 @@ cfg80211_find_sched_scan_req(struct cfg80211_registered_device *rdev, u64 reqid)
{ {
struct cfg80211_sched_scan_request *pos; struct cfg80211_sched_scan_request *pos;
WARN_ON_ONCE(!rcu_read_lock_held() && !lockdep_rtnl_is_held()); list_for_each_entry_rcu(pos, &rdev->sched_scan_req_list, list,
lockdep_rtnl_is_held()) {
list_for_each_entry_rcu(pos, &rdev->sched_scan_req_list, list) {
if (pos->reqid == reqid) if (pos->reqid == reqid)
return pos; return pos;
} }
...@@ -1434,8 +1433,7 @@ cfg80211_inform_single_bss_data(struct wiphy *wiphy, ...@@ -1434,8 +1433,7 @@ cfg80211_inform_single_bss_data(struct wiphy *wiphy,
} }
rcu_assign_pointer(tmp.pub.ies, ies); rcu_assign_pointer(tmp.pub.ies, ies);
signal_valid = abs(data->chan->center_freq - channel->center_freq) <= signal_valid = data->chan == channel;
wiphy->max_adj_channel_rssi_comp;
res = cfg80211_bss_update(wiphy_to_rdev(wiphy), &tmp, signal_valid, ts); res = cfg80211_bss_update(wiphy_to_rdev(wiphy), &tmp, signal_valid, ts);
if (!res) if (!res)
return NULL; return NULL;
...@@ -1852,8 +1850,7 @@ cfg80211_inform_single_bss_frame_data(struct wiphy *wiphy, ...@@ -1852,8 +1850,7 @@ cfg80211_inform_single_bss_frame_data(struct wiphy *wiphy,
memcpy(tmp.pub.chain_signal, data->chain_signal, IEEE80211_MAX_CHAINS); memcpy(tmp.pub.chain_signal, data->chain_signal, IEEE80211_MAX_CHAINS);
ether_addr_copy(tmp.parent_bssid, data->parent_bssid); ether_addr_copy(tmp.parent_bssid, data->parent_bssid);
signal_valid = abs(data->chan->center_freq - channel->center_freq) <= signal_valid = data->chan == channel;
wiphy->max_adj_channel_rssi_comp;
res = cfg80211_bss_update(wiphy_to_rdev(wiphy), &tmp, signal_valid, res = cfg80211_bss_update(wiphy_to_rdev(wiphy), &tmp, signal_valid,
jiffies); jiffies);
if (!res) if (!res)
......
...@@ -1111,9 +1111,16 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, ...@@ -1111,9 +1111,16 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
* Delete all the keys ... pairwise keys can't really * Delete all the keys ... pairwise keys can't really
* exist any more anyway, but default keys might. * exist any more anyway, but default keys might.
*/ */
if (rdev->ops->del_key) if (rdev->ops->del_key) {
for (i = 0; i < 6; i++) int max_key_idx = 5;
if (wiphy_ext_feature_isset(
wdev->wiphy,
NL80211_EXT_FEATURE_BEACON_PROTECTION))
max_key_idx = 7;
for (i = 0; i <= max_key_idx; i++)
rdev_del_key(rdev, dev, i, false, NULL); rdev_del_key(rdev, dev, i, false, NULL);
}
rdev_set_qos_map(rdev, dev, NULL); rdev_set_qos_map(rdev, dev, NULL);
......
...@@ -510,6 +510,23 @@ TRACE_EVENT(rdev_set_default_mgmt_key, ...@@ -510,6 +510,23 @@ TRACE_EVENT(rdev_set_default_mgmt_key,
WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->key_index) WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->key_index)
); );
TRACE_EVENT(rdev_set_default_beacon_key,
TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u8 key_index),
TP_ARGS(wiphy, netdev, key_index),
TP_STRUCT__entry(
WIPHY_ENTRY
NETDEV_ENTRY
__field(u8, key_index)
),
TP_fast_assign(
WIPHY_ASSIGN;
NETDEV_ASSIGN;
__entry->key_index = key_index;
),
TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", key index: %u",
WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->key_index)
);
TRACE_EVENT(rdev_start_ap, TRACE_EVENT(rdev_start_ap,
TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
struct cfg80211_ap_settings *settings), struct cfg80211_ap_settings *settings),
...@@ -1928,31 +1945,27 @@ TRACE_EVENT(rdev_mgmt_tx, ...@@ -1928,31 +1945,27 @@ TRACE_EVENT(rdev_mgmt_tx,
TRACE_EVENT(rdev_tx_control_port, TRACE_EVENT(rdev_tx_control_port,
TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
const u8 *buf, size_t len, const u8 *buf, size_t len, const u8 *dest, __be16 proto,
const u8 *dest, const u8 *src, __be16 proto,
bool unencrypted), bool unencrypted),
TP_ARGS(wiphy, netdev, buf, len, dest, src, proto, unencrypted), TP_ARGS(wiphy, netdev, buf, len, dest, proto, unencrypted),
TP_STRUCT__entry( TP_STRUCT__entry(
WIPHY_ENTRY WIPHY_ENTRY
NETDEV_ENTRY NETDEV_ENTRY
MAC_ENTRY(dest) MAC_ENTRY(dest)
MAC_ENTRY(src) __field(__be16, proto)
__field(u16, proto)
__field(bool, unencrypted) __field(bool, unencrypted)
), ),
TP_fast_assign( TP_fast_assign(
WIPHY_ASSIGN; WIPHY_ASSIGN;
NETDEV_ASSIGN; NETDEV_ASSIGN;
MAC_ASSIGN(dest, dest); MAC_ASSIGN(dest, dest);
MAC_ASSIGN(src, src); __entry->proto = proto;
__entry->proto = be16_to_cpu(proto);
__entry->unencrypted = unencrypted; __entry->unencrypted = unencrypted;
), ),
TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", dest: " MAC_PR_FMT TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " MAC_PR_FMT ","
", src: " MAC_PR_FMT ", proto: 0x%x, unencrypted: %s", " proto: 0x%x, unencrypted: %s",
WIPHY_PR_ARG, NETDEV_PR_ARG, WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(dest),
MAC_PR_ARG(dest), MAC_PR_ARG(src), be16_to_cpu(__entry->proto),
__entry->proto,
BOOL_TO_STR(__entry->unencrypted)) BOOL_TO_STR(__entry->unencrypted))
); );
...@@ -2844,7 +2857,6 @@ TRACE_EVENT(cfg80211_rx_control_port, ...@@ -2844,7 +2857,6 @@ TRACE_EVENT(cfg80211_rx_control_port,
TP_STRUCT__entry( TP_STRUCT__entry(
NETDEV_ENTRY NETDEV_ENTRY
__field(int, len) __field(int, len)
MAC_ENTRY(to)
MAC_ENTRY(from) MAC_ENTRY(from)
__field(u16, proto) __field(u16, proto)
__field(bool, unencrypted) __field(bool, unencrypted)
...@@ -2852,14 +2864,12 @@ TRACE_EVENT(cfg80211_rx_control_port, ...@@ -2852,14 +2864,12 @@ TRACE_EVENT(cfg80211_rx_control_port,
TP_fast_assign( TP_fast_assign(
NETDEV_ASSIGN; NETDEV_ASSIGN;
__entry->len = skb->len; __entry->len = skb->len;
MAC_ASSIGN(to, eth_hdr(skb)->h_dest);
MAC_ASSIGN(from, eth_hdr(skb)->h_source); MAC_ASSIGN(from, eth_hdr(skb)->h_source);
__entry->proto = be16_to_cpu(skb->protocol); __entry->proto = be16_to_cpu(skb->protocol);
__entry->unencrypted = unencrypted; __entry->unencrypted = unencrypted;
), ),
TP_printk(NETDEV_PR_FMT ", len=%d, dest: " MAC_PR_FMT TP_printk(NETDEV_PR_FMT ", len=%d, " MAC_PR_FMT ", proto: 0x%x, unencrypted: %s",
", src: " MAC_PR_FMT ", proto: 0x%x, unencrypted: %s", NETDEV_PR_ARG, __entry->len, MAC_PR_ARG(from),
NETDEV_PR_ARG, __entry->len, MAC_PR_ARG(to), MAC_PR_ARG(from),
__entry->proto, BOOL_TO_STR(__entry->unencrypted)) __entry->proto, BOOL_TO_STR(__entry->unencrypted))
); );
...@@ -3470,6 +3480,43 @@ TRACE_EVENT(rdev_probe_mesh_link, ...@@ -3470,6 +3480,43 @@ TRACE_EVENT(rdev_probe_mesh_link,
WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(dest)) WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(dest))
); );
TRACE_EVENT(rdev_set_tid_config,
TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
struct cfg80211_tid_config *tid_conf),
TP_ARGS(wiphy, netdev, tid_conf),
TP_STRUCT__entry(
WIPHY_ENTRY
NETDEV_ENTRY
MAC_ENTRY(peer)
),
TP_fast_assign(
WIPHY_ASSIGN;
NETDEV_ASSIGN;
MAC_ASSIGN(peer, tid_conf->peer);
),
TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", peer: " MAC_PR_FMT,
WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer))
);
TRACE_EVENT(rdev_reset_tid_config,
TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
const u8 *peer, u8 tids),
TP_ARGS(wiphy, netdev, peer, tids),
TP_STRUCT__entry(
WIPHY_ENTRY
NETDEV_ENTRY
MAC_ENTRY(peer)
__field(u8, tids)
),
TP_fast_assign(
WIPHY_ASSIGN;
NETDEV_ASSIGN;
MAC_ASSIGN(peer, peer);
__entry->tids = tids;
),
TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", peer: " MAC_PR_FMT ", tids: 0x%x",
WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer), __entry->tids)
);
#endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */ #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */
#undef TRACE_INCLUDE_PATH #undef TRACE_INCLUDE_PATH
......
...@@ -231,7 +231,12 @@ int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, ...@@ -231,7 +231,12 @@ int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
struct key_params *params, int key_idx, struct key_params *params, int key_idx,
bool pairwise, const u8 *mac_addr) bool pairwise, const u8 *mac_addr)
{ {
if (key_idx < 0 || key_idx > 5) int max_key_idx = 5;
if (wiphy_ext_feature_isset(&rdev->wiphy,
NL80211_EXT_FEATURE_BEACON_PROTECTION))
max_key_idx = 7;
if (key_idx < 0 || key_idx > max_key_idx)
return -EINVAL; return -EINVAL;
if (!pairwise && mac_addr && !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN)) if (!pairwise && mac_addr && !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment