Skip to content

Commit

Permalink
cfg80211: Support key configuration for Beacon protection (BIGTK)
Browse files Browse the repository at this point in the history
IEEE P802.11-REVmd/D3.0 adds support for protecting Beacon frames using
a new set of keys (BIGTK; key index 6..7) similarly to the way
group-addressed Robust Management frames are protected (IGTK; key index
4..5). Extend cfg80211 and nl80211 to allow the new BIGTK to be
configured. Add an extended feature flag to indicate driver support for
the new key index values to avoid array overflows in driver
implementations and also to indicate to user space when this
functionality is available.

Signed-off-by: Jouni Malinen <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
Signed-off-by: Johannes Berg <[email protected]>
  • Loading branch information
Jouni Malinen authored and jmberg-intel committed Feb 24, 2020
1 parent f8af764 commit 56be393
Show file tree
Hide file tree
Showing 7 changed files with 101 additions and 14 deletions.
5 changes: 5 additions & 0 deletions include/net/cfg80211.h
Original file line number Diff line number Diff line change
Expand Up @@ -3369,6 +3369,8 @@ struct cfg80211_update_owe_info {
* @set_default_key: set the default key on an interface
*
* @set_default_mgmt_key: set the default management frame key on an interface
* @set_default_beacon_key: set the default Beacon frame key on an interface
*
* @set_rekey_data: give the data necessary for GTK rekeying to the driver
*
Expand Down Expand Up @@ -3702,6 +3704,9 @@ struct cfg80211_ops {
int (*set_default_mgmt_key)(struct wiphy *wiphy,
struct net_device *netdev,
u8 key_index);
int (*set_default_beacon_key)(struct wiphy *wiphy,
struct net_device *netdev,
u8 key_index);

int (*start_ap)(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_ap_settings *settings);
Expand Down
6 changes: 6 additions & 0 deletions include/uapi/linux/nl80211.h
Original file line number Diff line number Diff line change
Expand Up @@ -4550,6 +4550,7 @@ 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_DEFAULT_BEACON: flag indicating default Beacon frame key
*
* @__NL80211_KEY_AFTER_LAST: internal
* @NL80211_KEY_MAX: highest key attribute
Expand All @@ -4565,6 +4566,7 @@ enum nl80211_key_attributes {
NL80211_KEY_TYPE,
NL80211_KEY_DEFAULT_TYPES,
NL80211_KEY_MODE,
NL80211_KEY_DEFAULT_BEACON,

/* keep last */
__NL80211_KEY_AFTER_LAST,
Expand Down Expand Up @@ -5539,6 +5541,9 @@ enum nl80211_feature_flags {
* feature, which prevents bufferbloat by using the expected transmission
* time to limit the amount of data buffered in the hardware.
*
* @NL80211_EXT_FEATURE_BEACON_PROTECTION: The driver supports Beacon protection
* and can receive key configuration for BIGTK using key indexes 6 and 7.
*
* @NUM_NL80211_EXT_FEATURES: number of extended features.
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
*/
Expand Down Expand Up @@ -5586,6 +5591,7 @@ enum nl80211_ext_feature_index {
NL80211_EXT_FEATURE_SAE_OFFLOAD,
NL80211_EXT_FEATURE_VLAN_OFFLOAD,
NL80211_EXT_FEATURE_AQL,
NL80211_EXT_FEATURE_BEACON_PROTECTION,

/* add new features before the definition below */
NUM_NL80211_EXT_FEATURES,
Expand Down
56 changes: 45 additions & 11 deletions net/wireless/nl80211.c
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
[NL80211_ATTR_KEY] = { .type = NLA_NESTED, },
[NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY,
.len = WLAN_MAX_KEY_LEN },
[NL80211_ATTR_KEY_IDX] = NLA_POLICY_MAX(NLA_U8, 5),
[NL80211_ATTR_KEY_IDX] = NLA_POLICY_MAX(NLA_U8, 7),
[NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 },
[NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG },
[NL80211_ATTR_KEY_SEQ] = { .type = NLA_BINARY, .len = 16 },
Expand Down Expand Up @@ -1037,7 +1037,7 @@ struct key_parse {
struct key_params p;
int idx;
int type;
bool def, defmgmt;
bool def, defmgmt, defbeacon;
bool def_uni, def_multi;
};

Expand All @@ -1053,12 +1053,13 @@ static int nl80211_parse_key_new(struct genl_info *info, struct nlattr *key,

k->def = !!tb[NL80211_KEY_DEFAULT];
k->defmgmt = !!tb[NL80211_KEY_DEFAULT_MGMT];
k->defbeacon = !!tb[NL80211_KEY_DEFAULT_BEACON];

if (k->def) {
k->def_uni = true;
k->def_multi = true;
}
if (k->defmgmt)
if (k->defmgmt || k->defbeacon)
k->def_multi = true;

if (tb[NL80211_KEY_IDX])
Expand Down Expand Up @@ -1165,14 +1166,17 @@ static int nl80211_parse_key(struct genl_info *info, struct key_parse *k)
if (err)
return err;

if (k->def && k->defmgmt) {
GENL_SET_ERR_MSG(info, "key with def && defmgmt is invalid");
if ((k->def ? 1 : 0) + (k->defmgmt ? 1 : 0) +
(k->defbeacon ? 1 : 0) > 1) {
GENL_SET_ERR_MSG(info,
"key with multiple default flags is invalid");
return -EINVAL;
}

if (k->defmgmt) {
if (k->defmgmt || k->defbeacon) {
if (k->def_uni || !k->def_multi) {
GENL_SET_ERR_MSG(info, "defmgmt key must be mcast");
GENL_SET_ERR_MSG(info,
"defmgmt/defbeacon key must be mcast");
return -EINVAL;
}
}
Expand All @@ -1184,14 +1188,20 @@ static int nl80211_parse_key(struct genl_info *info, struct key_parse *k)
"defmgmt key idx not 4 or 5");
return -EINVAL;
}
} else if (k->defbeacon) {
if (k->idx < 6 || k->idx > 7) {
GENL_SET_ERR_MSG(info,
"defbeacon key idx not 6 or 7");
return -EINVAL;
}
} else if (k->def) {
if (k->idx < 0 || k->idx > 3) {
GENL_SET_ERR_MSG(info, "def key idx not 0-3");
return -EINVAL;
}
} else {
if (k->idx < 0 || k->idx > 5) {
GENL_SET_ERR_MSG(info, "key idx not 0-5");
if (k->idx < 0 || k->idx > 7) {
GENL_SET_ERR_MSG(info, "key idx not 0-7");
return -EINVAL;
}
}
Expand Down Expand Up @@ -3817,8 +3827,14 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
void *hdr;
struct sk_buff *msg;

if (info->attrs[NL80211_ATTR_KEY_IDX])
if (info->attrs[NL80211_ATTR_KEY_IDX]) {
key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
if (key_idx > 5 &&
!wiphy_ext_feature_isset(
&rdev->wiphy,
NL80211_EXT_FEATURE_BEACON_PROTECTION))
return -EINVAL;
}

if (info->attrs[NL80211_ATTR_MAC])
mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
Expand Down Expand Up @@ -3894,7 +3910,7 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
/* Only support setting default key and
* Extended Key ID action NL80211_KEY_SET_TX.
*/
if (!key.def && !key.defmgmt &&
if (!key.def && !key.defmgmt && !key.defbeacon &&
!(key.p.mode == NL80211_KEY_SET_TX))
return -EINVAL;

Expand Down Expand Up @@ -3941,6 +3957,24 @@ 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 (key.defbeacon) {
if (key.def_uni || !key.def_multi) {
err = -EINVAL;
goto out;
}

if (!rdev->ops->set_default_beacon_key) {
err = -EOPNOTSUPP;
goto out;
}

err = nl80211_key_allowed(dev->ieee80211_ptr);
if (err)
goto out;

err = rdev_set_default_beacon_key(rdev, dev, key.idx);
if (err)
goto out;
} else if (key.p.mode == NL80211_KEY_SET_TX &&
wiphy_ext_feature_isset(&rdev->wiphy,
NL80211_EXT_FEATURE_EXT_KEY_ID)) {
Expand Down
13 changes: 13 additions & 0 deletions net/wireless/rdev-ops.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,19 @@ rdev_set_default_mgmt_key(struct cfg80211_registered_device *rdev,
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,
struct net_device *dev,
struct cfg80211_ap_settings *settings)
Expand Down
11 changes: 9 additions & 2 deletions net/wireless/sme.c
Original file line number Diff line number Diff line change
Expand Up @@ -1111,9 +1111,16 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
* Delete all the keys ... pairwise keys can't really
* exist any more anyway, but default keys might.
*/
if (rdev->ops->del_key)
for (i = 0; i < 6; i++)
if (rdev->ops->del_key) {
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_set_qos_map(rdev, dev, NULL);

Expand Down
17 changes: 17 additions & 0 deletions net/wireless/trace.h
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,23 @@ TRACE_EVENT(rdev_set_default_mgmt_key,
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,
TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
struct cfg80211_ap_settings *settings),
Expand Down
7 changes: 6 additions & 1 deletion net/wireless/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,12 @@ int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
struct key_params *params, int key_idx,
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;

if (!pairwise && mac_addr && !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN))
Expand Down

0 comments on commit 56be393

Please sign in to comment.