Commit 6cdd3979 authored by Alexander Wetzel's avatar Alexander Wetzel Committed by Johannes Berg

nl80211/cfg80211: Extended Key ID support

Add support for IEEE 802.11-2016 "Extended Key ID for Individually
Addressed Frames".

Extend cfg80211 and nl80211 to allow pairwise keys to be installed for
Rx only, enable Tx separately and allow Key ID 1 for pairwise keys.
Signed-off-by: default avatarAlexander Wetzel <alexander@wetzel-home.de>
[use NLA_POLICY_RANGE() for NL80211_KEY_MODE]
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 092c4098
...@@ -485,6 +485,7 @@ struct vif_params { ...@@ -485,6 +485,7 @@ struct vif_params {
* with the get_key() callback, must be in little endian, * with the get_key() callback, must be in little endian,
* length given by @seq_len. * length given by @seq_len.
* @seq_len: length of @seq. * @seq_len: length of @seq.
* @mode: key install mode (RX_TX, NO_TX or SET_TX)
*/ */
struct key_params { struct key_params {
const u8 *key; const u8 *key;
...@@ -492,6 +493,7 @@ struct key_params { ...@@ -492,6 +493,7 @@ struct key_params {
int key_len; int key_len;
int seq_len; int seq_len;
u32 cipher; u32 cipher;
enum nl80211_key_mode mode;
}; };
/** /**
......
...@@ -4152,6 +4152,27 @@ enum nl80211_channel_type { ...@@ -4152,6 +4152,27 @@ enum nl80211_channel_type {
NL80211_CHAN_HT40PLUS NL80211_CHAN_HT40PLUS
}; };
/**
* enum nl80211_key_mode - Key mode
*
* @NL80211_KEY_RX_TX: (Default)
* Key can be used for Rx and Tx immediately
*
* The following modes can only be selected for unicast keys and when the
* driver supports @NL80211_EXT_FEATURE_EXT_KEY_ID:
*
* @NL80211_KEY_NO_TX: Only allowed in combination with @NL80211_CMD_NEW_KEY:
* Unicast key can only be used for Rx, Tx not allowed, yet
* @NL80211_KEY_SET_TX: Only allowed in combination with @NL80211_CMD_SET_KEY:
* The unicast key identified by idx and mac is cleared for Tx and becomes
* the preferred Tx key for the station.
*/
enum nl80211_key_mode {
NL80211_KEY_RX_TX,
NL80211_KEY_NO_TX,
NL80211_KEY_SET_TX
};
/** /**
* enum nl80211_chan_width - channel width definitions * enum nl80211_chan_width - channel width definitions
* *
...@@ -4395,6 +4416,9 @@ enum nl80211_key_default_types { ...@@ -4395,6 +4416,9 @@ enum nl80211_key_default_types {
* @NL80211_KEY_DEFAULT_TYPES: A nested attribute containing flags * @NL80211_KEY_DEFAULT_TYPES: A nested attribute containing flags
* attributes, specifying what a key should be set as default as. * attributes, specifying what a key should be set as default as.
* See &enum nl80211_key_default_types. * See &enum nl80211_key_default_types.
* @NL80211_KEY_MODE: the mode from enum nl80211_key_mode.
* Defaults to @NL80211_KEY_RX_TX.
*
* @__NL80211_KEY_AFTER_LAST: internal * @__NL80211_KEY_AFTER_LAST: internal
* @NL80211_KEY_MAX: highest key attribute * @NL80211_KEY_MAX: highest key attribute
*/ */
...@@ -4408,6 +4432,7 @@ enum nl80211_key_attributes { ...@@ -4408,6 +4432,7 @@ enum nl80211_key_attributes {
NL80211_KEY_DEFAULT_MGMT, NL80211_KEY_DEFAULT_MGMT,
NL80211_KEY_TYPE, NL80211_KEY_TYPE,
NL80211_KEY_DEFAULT_TYPES, NL80211_KEY_DEFAULT_TYPES,
NL80211_KEY_MODE,
/* keep last */ /* keep last */
__NL80211_KEY_AFTER_LAST, __NL80211_KEY_AFTER_LAST,
...@@ -5353,6 +5378,8 @@ enum nl80211_feature_flags { ...@@ -5353,6 +5378,8 @@ enum nl80211_feature_flags {
* able to rekey an in-use key correctly. Userspace must not rekey PTK keys * 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 * if this flag is not set. Ignoring this can leak clear text packets and/or
* freeze the connection. * freeze the connection.
* @NL80211_EXT_FEATURE_EXT_KEY_ID: Driver supports "Extended Key ID for
* Individually Addressed Frames" from IEEE802.11-2016.
* *
* @NL80211_EXT_FEATURE_AIRTIME_FAIRNESS: Driver supports getting airtime * @NL80211_EXT_FEATURE_AIRTIME_FAIRNESS: Driver supports getting airtime
* fairness for transmitted packets and has enabled airtime fairness * fairness for transmitted packets and has enabled airtime fairness
...@@ -5406,6 +5433,7 @@ enum nl80211_ext_feature_index { ...@@ -5406,6 +5433,7 @@ enum nl80211_ext_feature_index {
NL80211_EXT_FEATURE_AIRTIME_FAIRNESS, NL80211_EXT_FEATURE_AIRTIME_FAIRNESS,
NL80211_EXT_FEATURE_AP_PMKSA_CACHING, NL80211_EXT_FEATURE_AP_PMKSA_CACHING,
NL80211_EXT_FEATURE_SCHED_SCAN_BAND_SPECIFIC_RSSI_THOLD, NL80211_EXT_FEATURE_SCHED_SCAN_BAND_SPECIFIC_RSSI_THOLD,
NL80211_EXT_FEATURE_EXT_KEY_ID,
/* add new features before the definition below */ /* add new features before the definition below */
NUM_NL80211_EXT_FEATURES, NUM_NL80211_EXT_FEATURES,
......
...@@ -553,6 +553,7 @@ static const struct nla_policy nl80211_key_policy[NL80211_KEY_MAX + 1] = { ...@@ -553,6 +553,7 @@ static const struct nla_policy nl80211_key_policy[NL80211_KEY_MAX + 1] = {
[NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG }, [NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG },
[NL80211_KEY_TYPE] = NLA_POLICY_MAX(NLA_U32, NUM_NL80211_KEYTYPES - 1), [NL80211_KEY_TYPE] = NLA_POLICY_MAX(NLA_U32, NUM_NL80211_KEYTYPES - 1),
[NL80211_KEY_DEFAULT_TYPES] = { .type = NLA_NESTED }, [NL80211_KEY_DEFAULT_TYPES] = { .type = NLA_NESTED },
[NL80211_KEY_MODE] = NLA_POLICY_RANGE(NLA_U8, 0, NL80211_KEY_SET_TX),
}; };
/* policy for the key default flags */ /* policy for the key default flags */
...@@ -967,6 +968,9 @@ static int nl80211_parse_key_new(struct genl_info *info, struct nlattr *key, ...@@ -967,6 +968,9 @@ static int nl80211_parse_key_new(struct genl_info *info, struct nlattr *key,
k->def_multi = kdt[NL80211_KEY_DEFAULT_TYPE_MULTICAST]; k->def_multi = kdt[NL80211_KEY_DEFAULT_TYPE_MULTICAST];
} }
if (tb[NL80211_KEY_MODE])
k->p.mode = nla_get_u8(tb[NL80211_KEY_MODE]);
return 0; return 0;
} }
...@@ -3643,8 +3647,11 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) ...@@ -3643,8 +3647,11 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
if (key.idx < 0) if (key.idx < 0)
return -EINVAL; return -EINVAL;
/* only support setting default key */ /* Only support setting default key and
if (!key.def && !key.defmgmt) * Extended Key ID action NL80211_KEY_SET_TX.
*/
if (!key.def && !key.defmgmt &&
!(key.p.mode == NL80211_KEY_SET_TX))
return -EINVAL; return -EINVAL;
wdev_lock(dev->ieee80211_ptr); wdev_lock(dev->ieee80211_ptr);
...@@ -3668,7 +3675,7 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) ...@@ -3668,7 +3675,7 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
#ifdef CONFIG_CFG80211_WEXT #ifdef CONFIG_CFG80211_WEXT
dev->ieee80211_ptr->wext.default_key = key.idx; dev->ieee80211_ptr->wext.default_key = key.idx;
#endif #endif
} else { } else if (key.defmgmt) {
if (key.def_uni || !key.def_multi) { if (key.def_uni || !key.def_multi) {
err = -EINVAL; err = -EINVAL;
goto out; goto out;
...@@ -3690,8 +3697,25 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) ...@@ -3690,8 +3697,25 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
#ifdef CONFIG_CFG80211_WEXT #ifdef CONFIG_CFG80211_WEXT
dev->ieee80211_ptr->wext.default_mgmt_key = key.idx; dev->ieee80211_ptr->wext.default_mgmt_key = key.idx;
#endif #endif
} } else if (key.p.mode == NL80211_KEY_SET_TX &&
wiphy_ext_feature_isset(&rdev->wiphy,
NL80211_EXT_FEATURE_EXT_KEY_ID)) {
u8 *mac_addr = NULL;
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 = -EINVAL;
goto out;
}
err = rdev_add_key(rdev, dev, key.idx,
NL80211_KEYTYPE_PAIRWISE,
mac_addr, &key.p);
} else {
err = -EINVAL;
}
out: out:
wdev_unlock(dev->ieee80211_ptr); wdev_unlock(dev->ieee80211_ptr);
......
...@@ -77,7 +77,8 @@ static inline int rdev_add_key(struct cfg80211_registered_device *rdev, ...@@ -77,7 +77,8 @@ static inline int rdev_add_key(struct cfg80211_registered_device *rdev,
struct key_params *params) struct key_params *params)
{ {
int ret; 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->mode);
ret = rdev->ops->add_key(&rdev->wiphy, netdev, key_index, pairwise, ret = rdev->ops->add_key(&rdev->wiphy, netdev, key_index, pairwise,
mac_addr, params); mac_addr, params);
trace_rdev_return_int(&rdev->wiphy, ret); trace_rdev_return_int(&rdev->wiphy, ret);
......
...@@ -430,22 +430,43 @@ DECLARE_EVENT_CLASS(key_handle, ...@@ -430,22 +430,43 @@ DECLARE_EVENT_CLASS(key_handle,
BOOL_TO_STR(__entry->pairwise), MAC_PR_ARG(mac_addr)) 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, TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
bool pairwise, const u8 *mac_addr), bool pairwise, const u8 *mac_addr),
TP_ARGS(wiphy, netdev, key_index, pairwise, 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, TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
bool pairwise, const u8 *mac_addr), bool pairwise, const u8 *mac_addr),
TP_ARGS(wiphy, netdev, key_index, pairwise, 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, TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
bool pairwise, const u8 *mac_addr), bool pairwise, const u8 *mac_addr, u8 mode),
TP_ARGS(wiphy, netdev, key_index, pairwise, mac_addr) TP_ARGS(wiphy, netdev, key_index, pairwise, mac_addr, mode),
TP_STRUCT__entry(
WIPHY_ENTRY
NETDEV_ENTRY
MAC_ENTRY(mac_addr)
__field(u8, key_index)
__field(bool, pairwise)
__field(u8, mode)
),
TP_fast_assign(
WIPHY_ASSIGN;
NETDEV_ASSIGN;
MAC_ASSIGN(mac_addr, mac_addr);
__entry->key_index = key_index;
__entry->pairwise = pairwise;
__entry->mode = mode;
),
TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", key_index: %u, "
"mode: %u, pairwise: %s, mac addr: " MAC_PR_FMT,
WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->key_index,
__entry->mode, BOOL_TO_STR(__entry->pairwise),
MAC_PR_ARG(mac_addr))
); );
TRACE_EVENT(rdev_set_default_key, TRACE_EVENT(rdev_set_default_key,
......
...@@ -237,14 +237,23 @@ int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, ...@@ -237,14 +237,23 @@ int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
case WLAN_CIPHER_SUITE_CCMP_256: case WLAN_CIPHER_SUITE_CCMP_256:
case WLAN_CIPHER_SUITE_GCMP: case WLAN_CIPHER_SUITE_GCMP:
case WLAN_CIPHER_SUITE_GCMP_256: case WLAN_CIPHER_SUITE_GCMP_256:
/* Disallow pairwise keys with non-zero index unless it's WEP /* IEEE802.11-2016 allows only 0 and - when using Extended Key
* or a vendor specific cipher (because current deployments use * ID - 1 as index for pairwise keys.
* pairwise WEP keys with non-zero indices and for vendor * @NL80211_KEY_NO_TX is only allowed for pairwise keys when
* specific ciphers this should be validated in the driver or * the driver supports Extended Key ID.
* hardware level - but 802.11i clearly specifies to use zero) * @NL80211_KEY_SET_TX can't be set when installing and
* validating a key.
*/ */
if (pairwise && key_idx) if (params->mode == NL80211_KEY_NO_TX) {
if (!wiphy_ext_feature_isset(&rdev->wiphy,
NL80211_EXT_FEATURE_EXT_KEY_ID))
return -EINVAL;
else if (!pairwise || key_idx < 0 || key_idx > 1)
return -EINVAL;
} else if ((pairwise && key_idx) ||
params->mode == NL80211_KEY_SET_TX) {
return -EINVAL; return -EINVAL;
}
break; break;
case WLAN_CIPHER_SUITE_AES_CMAC: case WLAN_CIPHER_SUITE_AES_CMAC:
case WLAN_CIPHER_SUITE_BIP_CMAC_256: case WLAN_CIPHER_SUITE_BIP_CMAC_256:
......
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