|
@@ -123,6 +123,9 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
|
|
|
[NL80211_ATTR_FREQ_FIXED] = { .type = NLA_FLAG },
|
|
|
[NL80211_ATTR_TIMED_OUT] = { .type = NLA_FLAG },
|
|
|
[NL80211_ATTR_USE_MFP] = { .type = NLA_U32 },
|
|
|
+ [NL80211_ATTR_STA_FLAGS2] = {
|
|
|
+ .len = sizeof(struct nl80211_sta_flag_update),
|
|
|
+ },
|
|
|
};
|
|
|
|
|
|
/* IE validation */
|
|
@@ -1334,13 +1337,33 @@ static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = {
|
|
|
[NL80211_STA_FLAG_MFP] = { .type = NLA_FLAG },
|
|
|
};
|
|
|
|
|
|
-static int parse_station_flags(struct nlattr *nla, u32 *staflags)
|
|
|
+static int parse_station_flags(struct genl_info *info,
|
|
|
+ struct station_parameters *params)
|
|
|
{
|
|
|
struct nlattr *flags[NL80211_STA_FLAG_MAX + 1];
|
|
|
+ struct nlattr *nla;
|
|
|
int flag;
|
|
|
|
|
|
- *staflags = 0;
|
|
|
+ /*
|
|
|
+ * Try parsing the new attribute first so userspace
|
|
|
+ * can specify both for older kernels.
|
|
|
+ */
|
|
|
+ nla = info->attrs[NL80211_ATTR_STA_FLAGS2];
|
|
|
+ if (nla) {
|
|
|
+ struct nl80211_sta_flag_update *sta_flags;
|
|
|
+
|
|
|
+ sta_flags = nla_data(nla);
|
|
|
+ params->sta_flags_mask = sta_flags->mask;
|
|
|
+ params->sta_flags_set = sta_flags->set;
|
|
|
+ if ((params->sta_flags_mask |
|
|
|
+ params->sta_flags_set) & BIT(__NL80211_STA_FLAG_INVALID))
|
|
|
+ return -EINVAL;
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* if present, parse the old attribute */
|
|
|
|
|
|
+ nla = info->attrs[NL80211_ATTR_STA_FLAGS];
|
|
|
if (!nla)
|
|
|
return 0;
|
|
|
|
|
@@ -1348,11 +1371,12 @@ static int parse_station_flags(struct nlattr *nla, u32 *staflags)
|
|
|
nla, sta_flags_policy))
|
|
|
return -EINVAL;
|
|
|
|
|
|
- *staflags = STATION_FLAG_CHANGED;
|
|
|
+ params->sta_flags_mask = (1 << __NL80211_STA_FLAG_AFTER_LAST) - 1;
|
|
|
+ params->sta_flags_mask &= ~1;
|
|
|
|
|
|
for (flag = 1; flag <= NL80211_STA_FLAG_MAX; flag++)
|
|
|
if (flags[flag])
|
|
|
- *staflags |= (1<<flag);
|
|
|
+ params->sta_flags_set |= (1<<flag);
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
@@ -1648,8 +1672,7 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
|
|
|
params.ht_capa =
|
|
|
nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]);
|
|
|
|
|
|
- if (parse_station_flags(info->attrs[NL80211_ATTR_STA_FLAGS],
|
|
|
- ¶ms.station_flags))
|
|
|
+ if (parse_station_flags(info, ¶ms))
|
|
|
return -EINVAL;
|
|
|
|
|
|
if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION])
|
|
@@ -1718,8 +1741,7 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
|
|
|
params.ht_capa =
|
|
|
nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]);
|
|
|
|
|
|
- if (parse_station_flags(info->attrs[NL80211_ATTR_STA_FLAGS],
|
|
|
- ¶ms.station_flags))
|
|
|
+ if (parse_station_flags(info, ¶ms))
|
|
|
return -EINVAL;
|
|
|
|
|
|
rtnl_lock();
|