cfg80211: Support key configuration for Beacon protection (BIGTK)
authorJouni Malinen <jouni@codeaurora.org>
Sat, 22 Feb 2020 13:25:43 +0000 (15:25 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Mon, 24 Feb 2020 09:35:48 +0000 (10:35 +0100)
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 <jouni@codeaurora.org>
Link: https://lore.kernel.org/r/20200222132548.20835-2-jouni@codeaurora.org
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
include/net/cfg80211.h
include/uapi/linux/nl80211.h
net/wireless/nl80211.c
net/wireless/rdev-ops.h
net/wireless/sme.c
net/wireless/trace.h
net/wireless/util.c

index 682ee4dd696352a6b047b941d8838e63a267853d..04b6df15706c5930099d04e4cfcfe051287ef90d 100644 (file)
@@ -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
  *
@@ -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);
index 350ab86fe20e809754fdc4ad51e2e856f9c8f9fa..934e62fe87057c425d926f93903bf1aefbd119f0 100644 (file)
@@ -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
@@ -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,
@@ -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.
  */
@@ -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,
index ce55a2c05fe91bdca12e7052c97e99292c72fff4..a75f7228813983e28a5c0cbbd79f2235fd362940 100644 (file)
@@ -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 },
@@ -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;
 };
 
@@ -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])
@@ -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;
                }
        }
@@ -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;
                        }
                }
@@ -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]);
@@ -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;
 
@@ -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)) {
index e0d34f796d0b3ab934cf7f8945bb0b86440c0285..af7fcf2a3b4aae5a22f8728df0084fb12fc91c1e 100644 (file)
@@ -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)
index d32a2ec4d96ace3b26b53bc8e895ab305961ae4b..ac3e60aa1fc8a786859657910ec439e220f146b5 100644 (file)
@@ -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);
 
index 3ef1679b0e667916fece6df7bdc55f0fa368b72a..56b78222746c3548755e033ce024cbf7c9efb057 100644 (file)
@@ -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),
index 8481e9ac33da5c71652186e8110b92e025eedae4..72926f87c91313d6b631c5fa0f75ea575a56abfa 100644 (file)
@@ -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))