cfg80211: Support key configuration for Beacon protection (BIGTK)
[openwrt/staging/blogic.git] / net / wireless / nl80211.c
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)) {