2018-11-10 15:21:49

by Alexander Wetzel

[permalink] [raw]
Subject: [RFC PATCH 0/2] Extended Key ID support for linux

IEEE 802.11-2012 added support for Extended Key ID, allowing pairwise
keys to also use keyID 1 and moving group keys to IDs 2 and 3.

Support for Extended Key ID is basically completed and confirmed working
with both hwsim and "on the air" with ath9k/iwldvm using software
encryption and those patches here.

(The corresponding patch for wpa_supplicanat/hostapd need some more
work, but that's mostly cleanup and support for STKSAs.)

Prior to propose this patch for merging I would like to get Extended
Key ID working with HW encryption for at least some devices, but after
experimenting with ath9k and to a lesser extend with ath10k it's now
clear that this will be an per-driver effort and it may well turn out to
be impossible without firmware updates.

So I've decided to continue working on the HW support for now but also
ask you for feedback for what I got so far.
Any feedback is welcome and I especially like to learn what you think of
the API extensions and what has to be changed to get it merged.

Alexander Wetzel (2):
nl80211/cfg80211: Add support for Extended Key ID
mac80211: Add support for Extended Key ID

include/net/cfg80211.h | 2 ++
include/net/mac80211.h | 6 +++++
include/uapi/linux/nl80211.h | 41 ++++++++++++++++++++++++++---
net/mac80211/cfg.c | 30 ++++++++++++++++++++-
net/mac80211/debugfs_sta.c | 1 +
net/mac80211/key.c | 46 +++++++++++++++++++++++++-------
net/mac80211/key.h | 1 +
net/mac80211/main.c | 2 ++
net/mac80211/sta_info.c | 1 +
net/mac80211/sta_info.h | 1 +
net/wireless/nl80211.c | 51 ++++++++++++++++++++++++++++++++----
net/wireless/rdev-ops.h | 3 ++-
net/wireless/trace.h | 31 ++++++++++++++++++----
net/wireless/util.c | 9 ++++---
14 files changed, 197 insertions(+), 28 deletions(-)

--
2.19.1



2018-11-10 15:22:03

by Alexander Wetzel

[permalink] [raw]
Subject: [RFC PATCH 1/2] nl80211/cfg80211: Add support for Extended Key ID

Extend cfg80211 and nl80211 to allow pairwise keys to be installed for
RX only and allowing to switching over TX independently, as required by
IEEE-802.11-2016 to support "Extended Key ID for Individually Addressed
Frames"
PTK and STK keys are now also allowed to use Key ID 1.

Signed-off-by: Alexander Wetzel <[email protected]>
---
include/net/cfg80211.h | 2 ++
include/uapi/linux/nl80211.h | 41 ++++++++++++++++++++++++++---
net/wireless/nl80211.c | 51 ++++++++++++++++++++++++++++++++----
net/wireless/rdev-ops.h | 3 ++-
net/wireless/trace.h | 31 ++++++++++++++++++----
net/wireless/util.c | 9 ++++---
6 files changed, 119 insertions(+), 18 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 1fa41b7a1be3..0d59340563e0 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -485,6 +485,7 @@ struct vif_params {
* with the get_key() callback, must be in little endian,
* length given by @seq_len.
* @seq_len: length of @seq.
+ * @flag: One flag from &enum key_params_flag
*/
struct key_params {
const u8 *key;
@@ -492,6 +493,7 @@ struct key_params {
int key_len;
int seq_len;
u32 cipher;
+ enum key_params_flag flag;
};

/**
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 6d610bae30a9..d6c7fa72f433 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -2254,6 +2254,14 @@ enum nl80211_commands {
* @NL80211_ATTR_FTM_RESPONDER_STATS: Nested attribute with FTM responder
* statistics, see &enum nl80211_ftm_responder_stats.
*
+ * @NL80211_ATTR_KEY_RXONLY: Flag attribute to request RX key install only for
+ * a pairwise key. Only supported for keyid's 0 and 1 when driver is
+ * supporting Extended Key ID.
+ *
+ * @NL80211_ATTR_KEY_SETTX: Flag attribute to switch TX to a specified keyid.
+ * Only supported for keyid's 0 and 1 when driver is supporting Extended
+ * Key ID.
+ *
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@@ -2699,6 +2707,9 @@ enum nl80211_attrs {

NL80211_ATTR_FTM_RESPONDER_STATS,

+ NL80211_ATTR_KEY_RXONLY,
+ NL80211_ATTR_KEY_SETTX,
+
/* add attributes here, update the policy in nl80211.c */

__NL80211_ATTR_AFTER_LAST,
@@ -4056,6 +4067,22 @@ enum nl80211_channel_type {
NL80211_CHAN_HT40PLUS
};

+/**
+ * enum key_params_flag - additional key flag for drivers
+ *
+ * Actions other than @NL80211_KEY_DEFAULT_RX_TX are only required from drivers
+ * supporting Extended Key ID for pairwise keys using keyid 0 or 1.
+ *
+ * @NL80211_KEY_DEFAULT_RX_TX: key can be immediately used for Rx and Tx
+ * @NL80211_KEY_RX_ONLY: key must be installed for Rx only
+ * @NL80211_KEY_SET_TX: switch Tx for sta to specified keyid
+ */
+enum key_params_flag {
+ NL80211_KEY_DEFAULT_RX_TX,
+ NL80211_KEY_RX_ONLY,
+ NL80211_KEY_SET_TX
+};
+
/**
* enum nl80211_chan_width - channel width definitions
*
@@ -4299,6 +4326,10 @@ enum nl80211_key_default_types {
* @NL80211_KEY_DEFAULT_TYPES: A nested attribute containing flags
* attributes, specifying what a key should be set as default as.
* See &enum nl80211_key_default_types.
+ * @NL80211_KEY_RXONLY: Flag attribute to request RX key install only for
+ * a pairwise key.
+ * @NL80211_KEY_SETTX: Flag attribute to switch TX to a selected key.
+ *
* @__NL80211_KEY_AFTER_LAST: internal
* @NL80211_KEY_MAX: highest key attribute
*/
@@ -4312,6 +4343,8 @@ enum nl80211_key_attributes {
NL80211_KEY_DEFAULT_MGMT,
NL80211_KEY_TYPE,
NL80211_KEY_DEFAULT_TYPES,
+ NL80211_KEY_RXONLY,
+ NL80211_KEY_SETTX,

/* keep last */
__NL80211_KEY_AFTER_LAST,
@@ -5250,13 +5283,14 @@ enum nl80211_feature_flags {
* @NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT: Driver/device can omit all data
* except for supported rates from the probe request content if requested
* by the %NL80211_SCAN_FLAG_MIN_PREQ_CONTENT flag.
- * @NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER: Driver supports enabling fine
- * timing measurement responder role.
- *
* @NL80211_EXT_FEATURE_CAN_REPLACE_PTK0: Driver/device confirm that they are
* able to rekey an in-use key correctly. Userspace must not rekey PTK keys
* if this flag is not set. Ignoring this can leak clear text packets and/or
* freeze the connection.
+ * @NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER: Driver supports enabling fine
+ * timing measurement responder role.
+ * @NL80211_EXT_FEATURE_EXT_KEY_ID: Driver supports "Extended Key ID for
+ * Individually Addressed Frames" from IEEE802.11-2016.
*
* @NUM_NL80211_EXT_FEATURES: number of extended features.
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
@@ -5297,6 +5331,7 @@ enum nl80211_ext_feature_index {
NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT,
NL80211_EXT_FEATURE_CAN_REPLACE_PTK0,
NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER,
+ NL80211_EXT_FEATURE_EXT_KEY_ID,

/* add new features before the definition below */
NUM_NL80211_EXT_FEATURES,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 744b5851bbf9..51ba4c9bffc5 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -275,6 +275,8 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
[NL80211_ATTR_KEY_SEQ] = { .type = NLA_BINARY, .len = 16 },
[NL80211_ATTR_KEY_TYPE] =
NLA_POLICY_MAX(NLA_U32, NUM_NL80211_KEYTYPES),
+ [NL80211_ATTR_KEY_RXONLY] = { .type = NLA_FLAG },
+ [NL80211_ATTR_KEY_SETTX] = { .type = NLA_FLAG },

[NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 },
[NL80211_ATTR_DTIM_PERIOD] = { .type = NLA_U32 },
@@ -509,6 +511,8 @@ static const struct nla_policy nl80211_key_policy[NL80211_KEY_MAX + 1] = {
[NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG },
[NL80211_KEY_TYPE] = NLA_POLICY_MAX(NLA_U32, NUM_NL80211_KEYTYPES - 1),
[NL80211_KEY_DEFAULT_TYPES] = { .type = NLA_NESTED },
+ [NL80211_KEY_RXONLY] = { .type = NLA_FLAG },
+ [NL80211_KEY_SETTX] = { .type = NLA_FLAG },
};

/* policy for the key default flags */
@@ -860,6 +864,7 @@ struct key_parse {
int type;
bool def, defmgmt;
bool def_uni, def_multi;
+ bool rx_only, set_tx;
};

static int nl80211_parse_key_new(struct genl_info *info, struct nlattr *key,
@@ -881,6 +886,16 @@ static int nl80211_parse_key_new(struct genl_info *info, struct nlattr *key,
if (k->defmgmt)
k->def_multi = true;

+ k->rx_only = !!tb[NL80211_KEY_RXONLY];
+ k->set_tx = !!tb[NL80211_KEY_SETTX];
+
+ if (k->rx_only && k->set_tx)
+ return -EINVAL;
+ else if (k->rx_only)
+ k->p.flag = NL80211_KEY_RX_ONLY;
+ else if (k->set_tx)
+ k->p.flag = NL80211_KEY_SET_TX;
+
if (tb[NL80211_KEY_IDX])
k->idx = nla_get_u8(tb[NL80211_KEY_IDX]);

@@ -945,6 +960,16 @@ static int nl80211_parse_key_old(struct genl_info *info, struct key_parse *k)
if (k->defmgmt)
k->def_multi = true;

+ k->rx_only = !!info->attrs[NL80211_ATTR_KEY_RXONLY];
+ k->set_tx = !!info->attrs[NL80211_ATTR_KEY_SETTX];
+
+ if (k->rx_only && k->set_tx)
+ return -EINVAL;
+ else if (k->rx_only)
+ k->p.flag = NL80211_KEY_RX_ONLY;
+ else if (k->set_tx)
+ k->p.flag = NL80211_KEY_SET_TX;
+
if (info->attrs[NL80211_ATTR_KEY_TYPE])
k->type = nla_get_u32(info->attrs[NL80211_ATTR_KEY_TYPE]);

@@ -3471,6 +3496,7 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
struct key_parse key;
int err;
struct net_device *dev = info->user_ptr[1];
+ u8 *mac_addr = NULL;

err = nl80211_parse_key(info, &key);
if (err)
@@ -3479,8 +3505,9 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
if (key.idx < 0)
return -EINVAL;

- /* only support setting default key */
- if (!key.def && !key.defmgmt)
+ /* only support setting default key and
+ * Extended Key ID action NL80211_KEY_SET_TX */
+ if (!key.def && !key.defmgmt && !key.set_tx)
return -EINVAL;

wdev_lock(dev->ieee80211_ptr);
@@ -3504,7 +3531,7 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
#ifdef CONFIG_CFG80211_WEXT
dev->ieee80211_ptr->wext.default_key = key.idx;
#endif
- } else {
+ } else if (key.defmgmt){
if (key.def_uni || !key.def_multi) {
err = -EINVAL;
goto out;
@@ -3526,8 +3553,22 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
#ifdef CONFIG_CFG80211_WEXT
dev->ieee80211_ptr->wext.default_mgmt_key = key.idx;
#endif
- }
+ } else if (wiphy_ext_feature_isset(&rdev->wiphy,
+ NL80211_EXT_FEATURE_EXT_KEY_ID)) {
+ if (info->attrs[NL80211_ATTR_MAC])
+ mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);

+ if (!mac_addr || key.idx < 0 || key.idx > 1) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ err = rdev_add_key(rdev, dev, key.idx,
+ NL80211_KEYTYPE_PAIRWISE,
+ mac_addr, &key.p);
+ } else {
+ err = -EOPNOTSUPP;
+ }
out:
wdev_unlock(dev->ieee80211_ptr);

@@ -3546,7 +3587,7 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
if (err)
return err;

- if (!key.p.key)
+ if (!key.p.key || key.set_tx)
return -EINVAL;

if (info->attrs[NL80211_ATTR_MAC])
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
index 51380b5c32f2..bc2f6f26b729 100644
--- a/net/wireless/rdev-ops.h
+++ b/net/wireless/rdev-ops.h
@@ -77,7 +77,8 @@ static inline int rdev_add_key(struct cfg80211_registered_device *rdev,
struct key_params *params)
{
int ret;
- trace_rdev_add_key(&rdev->wiphy, netdev, key_index, pairwise, mac_addr);
+ trace_rdev_add_key(&rdev->wiphy, netdev, key_index, pairwise,
+ mac_addr, params->flag);
ret = rdev->ops->add_key(&rdev->wiphy, netdev, key_index, pairwise,
mac_addr, params);
trace_rdev_return_int(&rdev->wiphy, ret);
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index c6a9446b4e6b..903e4cda930c 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -412,22 +412,43 @@ DECLARE_EVENT_CLASS(key_handle,
BOOL_TO_STR(__entry->pairwise), MAC_PR_ARG(mac_addr))
);

-DEFINE_EVENT(key_handle, rdev_add_key,
+DEFINE_EVENT(key_handle, rdev_get_key,
TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
bool pairwise, const u8 *mac_addr),
TP_ARGS(wiphy, netdev, key_index, pairwise, mac_addr)
);

-DEFINE_EVENT(key_handle, rdev_get_key,
+DEFINE_EVENT(key_handle, rdev_del_key,
TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
bool pairwise, const u8 *mac_addr),
TP_ARGS(wiphy, netdev, key_index, pairwise, mac_addr)
);

-DEFINE_EVENT(key_handle, rdev_del_key,
+TRACE_EVENT(rdev_add_key,
TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
- bool pairwise, const u8 *mac_addr),
- TP_ARGS(wiphy, netdev, key_index, pairwise, mac_addr)
+ bool pairwise, const u8 *mac_addr, u8 flag),
+ TP_ARGS(wiphy, netdev, key_index, pairwise, mac_addr, flag),
+ TP_STRUCT__entry(
+ WIPHY_ENTRY
+ NETDEV_ENTRY
+ MAC_ENTRY(mac_addr)
+ __field(u8, key_index)
+ __field(bool, pairwise)
+ __field(u8, flag)
+ ),
+ TP_fast_assign(
+ WIPHY_ASSIGN;
+ NETDEV_ASSIGN;
+ MAC_ASSIGN(mac_addr, mac_addr);
+ __entry->key_index = key_index;
+ __entry->pairwise = pairwise;
+ __entry->flag = flag;
+ ),
+ TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", key_index: %u, flag: %u, "
+ "pairwise: %s, mac addr: " MAC_PR_FMT,
+ WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->key_index,
+ __entry->flag, BOOL_TO_STR(__entry->pairwise),
+ MAC_PR_ARG(mac_addr))
);

TRACE_EVENT(rdev_set_default_key,
diff --git a/net/wireless/util.c b/net/wireless/util.c
index ef14d80ca03e..3f2d116b8557 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -236,13 +236,14 @@ int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
case WLAN_CIPHER_SUITE_CCMP_256:
case WLAN_CIPHER_SUITE_GCMP:
case WLAN_CIPHER_SUITE_GCMP_256:
- /* Disallow pairwise keys with non-zero index unless it's WEP
+ /* IEEE802.11-2016 allows only 0 and 1 for pairwise keys.
+ * Disallow pairwise keys with index above 1 unless it's WEP
* or a vendor specific cipher (because current deployments use
- * pairwise WEP keys with non-zero indices and for vendor
+ * pairwise WEP keys with higher indices and for vendor
* specific ciphers this should be validated in the driver or
- * hardware level - but 802.11i clearly specifies to use zero)
+ * hardware level.
*/
- if (pairwise && key_idx)
+ if (pairwise && key_idx > 1)
return -EINVAL;
break;
case WLAN_CIPHER_SUITE_AES_CMAC:
--
2.19.1


2018-11-10 16:31:59

by Alexander Wetzel

[permalink] [raw]
Subject: [RFC PATCH 2/2] mac80211: Add support for Extended Key ID

Allow drivers using mac80211 to support Extended Key IDs.

Signed-off-by: Alexander Wetzel <[email protected]>
---
include/net/mac80211.h | 6 +++++
net/mac80211/cfg.c | 30 ++++++++++++++++++++++++-
net/mac80211/debugfs_sta.c | 1 +
net/mac80211/key.c | 46 ++++++++++++++++++++++++++++++--------
net/mac80211/key.h | 1 +
net/mac80211/main.c | 2 ++
net/mac80211/sta_info.c | 1 +
net/mac80211/sta_info.h | 1 +
8 files changed, 78 insertions(+), 10 deletions(-)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 71985e95d2d9..fb53e7c84c01 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1643,6 +1643,10 @@ 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_RX_ONLY: Set by mac80211 to indicate that the key
+ * must not be used for TX (yet).
+ * @IEEE80211_KEY_FLAG_SET_TX: Set by mac80211 to indicate that a previously
+ * installed key with IEEE80211_KEY_FLAG_RX_ONLY should take over TX also.
*/
enum ieee80211_key_flags {
IEEE80211_KEY_FLAG_GENERATE_IV_MGMT = BIT(0),
@@ -1654,6 +1658,8 @@ 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_RX_ONLY = BIT(9),
+ IEEE80211_KEY_FLAG_SET_TX = BIT(10),
};

/**
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 51622333d460..c0af820bc557 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -365,6 +365,25 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
if (!ieee80211_sdata_running(sdata))
return -ENETDOWN;

+ if (pairwise && params->flag == NL80211_KEY_SET_TX) {
+ mutex_lock(&local->sta_mtx);
+ sta = sta_info_get_bss(sdata, mac_addr);
+
+ if (!sta ||
+ !(key = rcu_dereference(sta->ptk[key_idx])) ||
+ !(key->conf.flags | IEEE80211_KEY_FLAG_RX_ONLY)) {
+ err = -ENOENT;
+ } else {
+ key->conf.flags &= ~IEEE80211_KEY_FLAG_RX_ONLY;
+ key->conf.flags |= IEEE80211_KEY_FLAG_SET_TX;
+ err = ieee80211_key_hw_activate_tx(key);
+ if (!err)
+ sta->ptk_idx = key_idx;
+ }
+ mutex_unlock(&local->sta_mtx);
+ return err;
+ }
+
/* reject WEP and TKIP keys if WEP failed to initialize */
switch (params->cipher) {
case WLAN_CIPHER_SUITE_WEP40:
@@ -451,9 +470,18 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
break;
}

- if (sta)
+ if (sta) {
sta->cipher_scheme = cs;

+ /* Flag STA correctly when using Extended Key ID */
+ if (pairwise && params->flag == NL80211_KEY_RX_ONLY &&
+ !test_sta_flag(sta, WLAN_STA_EXT_KEY_ID))
+ set_sta_flag(sta, WLAN_STA_EXT_KEY_ID);
+ }
+
+ if (params->flag == NL80211_KEY_RX_ONLY)
+ key->conf.flags |= IEEE80211_KEY_FLAG_RX_ONLY;
+
err = ieee80211_key_link(key, sdata, sta);

out_unlock:
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c
index af5185a836e5..d63dca26d504 100644
--- a/net/mac80211/debugfs_sta.c
+++ b/net/mac80211/debugfs_sta.c
@@ -81,6 +81,7 @@ static const char * const sta_flag_names[] = {
FLAG(MPSP_OWNER),
FLAG(MPSP_RECIPIENT),
FLAG(PS_DELIVER),
+ FLAG(EXT_KEY_ID),
#undef FLAG
};

diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index 4700718e010f..05aa30827f56 100644
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -124,6 +124,36 @@ static void decrease_tailroom_need_count(struct ieee80211_sub_if_data *sdata,
sdata->crypto_tx_tailroom_needed_cnt -= delta;
}

+int ieee80211_key_hw_activate_tx(struct ieee80211_key *key)
+{
+ struct ieee80211_sub_if_data *sdata = key->sdata;
+ struct sta_info *sta = key->sta;
+ int ret;
+
+ assert_key_lock(key->local);
+
+ if (!sta)
+ return -EOPNOTSUPP;
+
+ if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
+ /* No need to inform driver, report success */
+ return 0;
+
+ /* Inform driver that key is no longer RX only */
+ ret = drv_set_key(key->local, SET_KEY, sdata,
+ &sta->sta, &key->conf);
+ if (ret) {
+ if (ret == 1)
+ /* Software crypto, report success */
+ return 0;
+ sdata_err(sdata,
+ "failed to activate key for TX (%d, %pM) in hardware (%d)\n",
+ key->conf.keyidx,
+ sta->sta.addr, ret);
+ }
+ return ret;
+}
+
static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
{
struct ieee80211_sub_if_data *sdata = key->sdata;
@@ -261,12 +291,13 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)

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;
struct sta_info *sta;
int ret;
+ bool ext_key_id = test_sta_flag(sta, WLAN_STA_EXT_KEY_ID);

/* Aggregation sessions are OK when running on SW crypto.
* A broken remote STA may cause issues not observed with HW
@@ -278,8 +309,8 @@ 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) {
+ /* PTK rekey without Extended Key ID needs special handling */
+ if (new_key && pairwise && sta && !ext_key_id) {
local = old_key->local;
sdata = old_key->sdata;

@@ -395,10 +426,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 */
@@ -415,8 +442,9 @@ 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_RX_ONLY)) {
+ sta->ptk_idx = idx;
clear_sta_flag(sta, WLAN_STA_BLOCK_BA);
ieee80211_check_fast_xmit(sta);
}
diff --git a/net/mac80211/key.h b/net/mac80211/key.h
index ebdb80b85dc3..e0612a0b3adc 100644
--- a/net/mac80211/key.h
+++ b/net/mac80211/key.h
@@ -146,6 +146,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_key_hw_activate_tx(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,
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 83e71e6b2ebe..8a8ca813494a 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -574,6 +574,8 @@ 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_CONTROL_PORT_OVER_NL80211);
+ /* !! DEVELOPMENT ONLY, must normally be set by driver !! */
+ wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_EXT_KEY_ID);

if (!ops->hw_scan) {
wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index fb8c2252ac0e..2d83d8e13769 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -350,6 +350,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
sta->sta.max_rx_aggregation_subframes =
local->hw.max_rx_aggregation_subframes;

+ sta->ptk_idx = NUM_DEFAULT_KEYS - 1;
sta->local = local;
sta->sdata = sdata;
sta->rx_stats.last_rx = jiffies;
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 9a04327d71d1..7787e773a350 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -101,6 +101,7 @@ enum ieee80211_sta_info_flags {
WLAN_STA_MPSP_OWNER,
WLAN_STA_MPSP_RECIPIENT,
WLAN_STA_PS_DELIVER,
+ WLAN_STA_EXT_KEY_ID,

NUM_WLAN_STA_FLAGS,
};
--
2.19.1