nl80211: improve station flags handling
It is currently not possible to modify station flags, but that capability would be very useful. This patch introduces a new nl80211 attribute that contains a set/mask for station flags, and updates the internal API (and mac80211) to mirror that. The new attribute is parsed before falling back to the old so that userspace can specify both (if it can) to work on all kernels. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: Jouni Malinen <jouni.malinen@atheros.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
committed by
John W. Linville
parent
0e46724a48
commit
eccb8e8f0c
@@ -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();
|
||||
|
Reference in New Issue
Block a user