|
@@ -171,6 +171,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
|
|
[NL80211_ATTR_WIPHY_ANTENNA_RX] = { .type = NLA_U32 },
|
|
[NL80211_ATTR_WIPHY_ANTENNA_RX] = { .type = NLA_U32 },
|
|
[NL80211_ATTR_MCAST_RATE] = { .type = NLA_U32 },
|
|
[NL80211_ATTR_MCAST_RATE] = { .type = NLA_U32 },
|
|
[NL80211_ATTR_OFFCHANNEL_TX_OK] = { .type = NLA_FLAG },
|
|
[NL80211_ATTR_OFFCHANNEL_TX_OK] = { .type = NLA_FLAG },
|
|
|
|
+ [NL80211_ATTR_KEY_DEFAULT_TYPES] = { .type = NLA_NESTED },
|
|
};
|
|
};
|
|
|
|
|
|
/* policy for the key attributes */
|
|
/* policy for the key attributes */
|
|
@@ -182,6 +183,14 @@ static const struct nla_policy nl80211_key_policy[NL80211_KEY_MAX + 1] = {
|
|
[NL80211_KEY_DEFAULT] = { .type = NLA_FLAG },
|
|
[NL80211_KEY_DEFAULT] = { .type = NLA_FLAG },
|
|
[NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG },
|
|
[NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG },
|
|
[NL80211_KEY_TYPE] = { .type = NLA_U32 },
|
|
[NL80211_KEY_TYPE] = { .type = NLA_U32 },
|
|
|
|
+ [NL80211_KEY_DEFAULT_TYPES] = { .type = NLA_NESTED },
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+/* policy for the key default flags */
|
|
|
|
+static const struct nla_policy
|
|
|
|
+nl80211_key_default_policy[NUM_NL80211_KEY_DEFAULT_TYPES] = {
|
|
|
|
+ [NL80211_KEY_DEFAULT_TYPE_UNICAST] = { .type = NLA_FLAG },
|
|
|
|
+ [NL80211_KEY_DEFAULT_TYPE_MULTICAST] = { .type = NLA_FLAG },
|
|
};
|
|
};
|
|
|
|
|
|
/* ifidx get helper */
|
|
/* ifidx get helper */
|
|
@@ -314,6 +323,7 @@ struct key_parse {
|
|
int idx;
|
|
int idx;
|
|
int type;
|
|
int type;
|
|
bool def, defmgmt;
|
|
bool def, defmgmt;
|
|
|
|
+ bool def_uni, def_multi;
|
|
};
|
|
};
|
|
|
|
|
|
static int nl80211_parse_key_new(struct nlattr *key, struct key_parse *k)
|
|
static int nl80211_parse_key_new(struct nlattr *key, struct key_parse *k)
|
|
@@ -327,6 +337,13 @@ static int nl80211_parse_key_new(struct nlattr *key, struct key_parse *k)
|
|
k->def = !!tb[NL80211_KEY_DEFAULT];
|
|
k->def = !!tb[NL80211_KEY_DEFAULT];
|
|
k->defmgmt = !!tb[NL80211_KEY_DEFAULT_MGMT];
|
|
k->defmgmt = !!tb[NL80211_KEY_DEFAULT_MGMT];
|
|
|
|
|
|
|
|
+ if (k->def) {
|
|
|
|
+ k->def_uni = true;
|
|
|
|
+ k->def_multi = true;
|
|
|
|
+ }
|
|
|
|
+ if (k->defmgmt)
|
|
|
|
+ k->def_multi = true;
|
|
|
|
+
|
|
if (tb[NL80211_KEY_IDX])
|
|
if (tb[NL80211_KEY_IDX])
|
|
k->idx = nla_get_u8(tb[NL80211_KEY_IDX]);
|
|
k->idx = nla_get_u8(tb[NL80211_KEY_IDX]);
|
|
|
|
|
|
@@ -349,6 +366,19 @@ static int nl80211_parse_key_new(struct nlattr *key, struct key_parse *k)
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if (tb[NL80211_KEY_DEFAULT_TYPES]) {
|
|
|
|
+ struct nlattr *kdt[NUM_NL80211_KEY_DEFAULT_TYPES];
|
|
|
|
+ int err = nla_parse_nested(kdt,
|
|
|
|
+ NUM_NL80211_KEY_DEFAULT_TYPES - 1,
|
|
|
|
+ tb[NL80211_KEY_DEFAULT_TYPES],
|
|
|
|
+ nl80211_key_default_policy);
|
|
|
|
+ if (err)
|
|
|
|
+ return err;
|
|
|
|
+
|
|
|
|
+ k->def_uni = kdt[NL80211_KEY_DEFAULT_TYPE_UNICAST];
|
|
|
|
+ k->def_multi = kdt[NL80211_KEY_DEFAULT_TYPE_MULTICAST];
|
|
|
|
+ }
|
|
|
|
+
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -373,12 +403,32 @@ static int nl80211_parse_key_old(struct genl_info *info, struct key_parse *k)
|
|
k->def = !!info->attrs[NL80211_ATTR_KEY_DEFAULT];
|
|
k->def = !!info->attrs[NL80211_ATTR_KEY_DEFAULT];
|
|
k->defmgmt = !!info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT];
|
|
k->defmgmt = !!info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT];
|
|
|
|
|
|
|
|
+ if (k->def) {
|
|
|
|
+ k->def_uni = true;
|
|
|
|
+ k->def_multi = true;
|
|
|
|
+ }
|
|
|
|
+ if (k->defmgmt)
|
|
|
|
+ k->def_multi = true;
|
|
|
|
+
|
|
if (info->attrs[NL80211_ATTR_KEY_TYPE]) {
|
|
if (info->attrs[NL80211_ATTR_KEY_TYPE]) {
|
|
k->type = nla_get_u32(info->attrs[NL80211_ATTR_KEY_TYPE]);
|
|
k->type = nla_get_u32(info->attrs[NL80211_ATTR_KEY_TYPE]);
|
|
if (k->type < 0 || k->type >= NUM_NL80211_KEYTYPES)
|
|
if (k->type < 0 || k->type >= NUM_NL80211_KEYTYPES)
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if (info->attrs[NL80211_ATTR_KEY_DEFAULT_TYPES]) {
|
|
|
|
+ struct nlattr *kdt[NUM_NL80211_KEY_DEFAULT_TYPES];
|
|
|
|
+ int err = nla_parse_nested(
|
|
|
|
+ kdt, NUM_NL80211_KEY_DEFAULT_TYPES - 1,
|
|
|
|
+ info->attrs[NL80211_ATTR_KEY_DEFAULT_TYPES],
|
|
|
|
+ nl80211_key_default_policy);
|
|
|
|
+ if (err)
|
|
|
|
+ return err;
|
|
|
|
+
|
|
|
|
+ k->def_uni = kdt[NL80211_KEY_DEFAULT_TYPE_UNICAST];
|
|
|
|
+ k->def_multi = kdt[NL80211_KEY_DEFAULT_TYPE_MULTICAST];
|
|
|
|
+ }
|
|
|
|
+
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -401,6 +451,11 @@ static int nl80211_parse_key(struct genl_info *info, struct key_parse *k)
|
|
if (k->def && k->defmgmt)
|
|
if (k->def && k->defmgmt)
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
+ if (k->defmgmt) {
|
|
|
|
+ if (k->def_uni || !k->def_multi)
|
|
|
|
+ return -EINVAL;
|
|
|
|
+ }
|
|
|
|
+
|
|
if (k->idx != -1) {
|
|
if (k->idx != -1) {
|
|
if (k->defmgmt) {
|
|
if (k->defmgmt) {
|
|
if (k->idx < 4 || k->idx > 5)
|
|
if (k->idx < 4 || k->idx > 5)
|
|
@@ -450,6 +505,8 @@ nl80211_parse_connkeys(struct cfg80211_registered_device *rdev,
|
|
goto error;
|
|
goto error;
|
|
def = 1;
|
|
def = 1;
|
|
result->def = parse.idx;
|
|
result->def = parse.idx;
|
|
|
|
+ if (!parse.def_uni || !parse.def_multi)
|
|
|
|
+ goto error;
|
|
} else if (parse.defmgmt)
|
|
} else if (parse.defmgmt)
|
|
goto error;
|
|
goto error;
|
|
err = cfg80211_validate_key_settings(rdev, &parse.p,
|
|
err = cfg80211_validate_key_settings(rdev, &parse.p,
|
|
@@ -1586,8 +1643,6 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
|
|
struct key_parse key;
|
|
struct key_parse key;
|
|
int err;
|
|
int err;
|
|
struct net_device *dev = info->user_ptr[1];
|
|
struct net_device *dev = info->user_ptr[1];
|
|
- int (*func)(struct wiphy *wiphy, struct net_device *netdev,
|
|
|
|
- u8 key_index);
|
|
|
|
|
|
|
|
err = nl80211_parse_key(info, &key);
|
|
err = nl80211_parse_key(info, &key);
|
|
if (err)
|
|
if (err)
|
|
@@ -1600,27 +1655,61 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
|
|
if (!key.def && !key.defmgmt)
|
|
if (!key.def && !key.defmgmt)
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
|
|
|
|
- if (key.def)
|
|
|
|
- func = rdev->ops->set_default_key;
|
|
|
|
- else
|
|
|
|
- func = rdev->ops->set_default_mgmt_key;
|
|
|
|
|
|
+ wdev_lock(dev->ieee80211_ptr);
|
|
|
|
|
|
- if (!func)
|
|
|
|
- return -EOPNOTSUPP;
|
|
|
|
|
|
+ if (key.def) {
|
|
|
|
+ if (!rdev->ops->set_default_key) {
|
|
|
|
+ err = -EOPNOTSUPP;
|
|
|
|
+ goto out;
|
|
|
|
+ }
|
|
|
|
|
|
- wdev_lock(dev->ieee80211_ptr);
|
|
|
|
- err = nl80211_key_allowed(dev->ieee80211_ptr);
|
|
|
|
- if (!err)
|
|
|
|
- err = func(&rdev->wiphy, dev, key.idx);
|
|
|
|
|
|
+ err = nl80211_key_allowed(dev->ieee80211_ptr);
|
|
|
|
+ if (err)
|
|
|
|
+ goto out;
|
|
|
|
+
|
|
|
|
+ if (!(rdev->wiphy.flags &
|
|
|
|
+ WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS)) {
|
|
|
|
+ if (!key.def_uni || !key.def_multi) {
|
|
|
|
+ err = -EOPNOTSUPP;
|
|
|
|
+ goto out;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ err = rdev->ops->set_default_key(&rdev->wiphy, dev, key.idx,
|
|
|
|
+ key.def_uni, key.def_multi);
|
|
|
|
+
|
|
|
|
+ if (err)
|
|
|
|
+ goto out;
|
|
|
|
|
|
#ifdef CONFIG_CFG80211_WEXT
|
|
#ifdef CONFIG_CFG80211_WEXT
|
|
- if (!err) {
|
|
|
|
- if (func == rdev->ops->set_default_key)
|
|
|
|
- dev->ieee80211_ptr->wext.default_key = key.idx;
|
|
|
|
- else
|
|
|
|
- dev->ieee80211_ptr->wext.default_mgmt_key = key.idx;
|
|
|
|
- }
|
|
|
|
|
|
+ dev->ieee80211_ptr->wext.default_key = key.idx;
|
|
|
|
+#endif
|
|
|
|
+ } else {
|
|
|
|
+ if (key.def_uni || !key.def_multi) {
|
|
|
|
+ err = -EINVAL;
|
|
|
|
+ goto out;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (!rdev->ops->set_default_mgmt_key) {
|
|
|
|
+ err = -EOPNOTSUPP;
|
|
|
|
+ goto out;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ err = nl80211_key_allowed(dev->ieee80211_ptr);
|
|
|
|
+ if (err)
|
|
|
|
+ goto out;
|
|
|
|
+
|
|
|
|
+ err = rdev->ops->set_default_mgmt_key(&rdev->wiphy,
|
|
|
|
+ dev, key.idx);
|
|
|
|
+ if (err)
|
|
|
|
+ goto out;
|
|
|
|
+
|
|
|
|
+#ifdef CONFIG_CFG80211_WEXT
|
|
|
|
+ dev->ieee80211_ptr->wext.default_mgmt_key = key.idx;
|
|
#endif
|
|
#endif
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ out:
|
|
wdev_unlock(dev->ieee80211_ptr);
|
|
wdev_unlock(dev->ieee80211_ptr);
|
|
|
|
|
|
return err;
|
|
return err;
|