diff options
-rw-r--r-- | include/linux/nl80211.h | 21 | ||||
-rw-r--r-- | include/net/cfg80211.h | 28 | ||||
-rw-r--r-- | net/mac80211/cfg.c | 28 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 38 |
4 files changed, 71 insertions, 44 deletions
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 58c4ee1822d..aeefccfac0e 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -25,6 +25,8 @@ * */ +#include <linux/types.h> + /** * DOC: Station handling * @@ -380,7 +382,7 @@ enum nl80211_commands { * * @NL80211_ATTR_STA_AID: Association ID for the station (u16) * @NL80211_ATTR_STA_FLAGS: flags, nested element with NLA_FLAG attributes of - * &enum nl80211_sta_flags. + * &enum nl80211_sta_flags (deprecated, use %NL80211_ATTR_STA_FLAGS2) * @NL80211_ATTR_STA_LISTEN_INTERVAL: listen interval as defined by * IEEE 802.11 7.3.1.6 (u16). * @NL80211_ATTR_STA_SUPPORTED_RATES: supported rates, array of supported @@ -499,6 +501,9 @@ enum nl80211_commands { * this attribute can be used * with %NL80211_CMD_ASSOCIATE request * + * @NL80211_ATTR_STA_FLAGS2: Attribute containing a + * &struct nl80211_sta_flag_update. + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -603,6 +608,8 @@ enum nl80211_attrs { NL80211_ATTR_USE_MFP, + NL80211_ATTR_STA_FLAGS2, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -692,6 +699,18 @@ enum nl80211_sta_flags { }; /** + * struct nl80211_sta_flag_update - station flags mask/set + * @mask: mask of station flags to set + * @set: which values to set them to + * + * Both mask and set contain bits as per &enum nl80211_sta_flags. + */ +struct nl80211_sta_flag_update { + __u32 mask; + __u32 set; +} __attribute__((packed)); + +/** * enum nl80211_rate_info - bitrate information * * These attribute types are used with %NL80211_STA_INFO_TXRATE diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index e69e6c66dd1..0dae6b38294 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -252,27 +252,6 @@ struct beacon_parameters { }; /** - * enum station_flags - station flags - * - * Station capability flags. Note that these must be the bits - * according to the nl80211 flags. - * - * @STATION_FLAG_CHANGED: station flags were changed - * @STATION_FLAG_AUTHORIZED: station is authorized to send frames (802.1X) - * @STATION_FLAG_SHORT_PREAMBLE: station is capable of receiving frames - * with short preambles - * @STATION_FLAG_WME: station is WME/QoS capable - * @STATION_FLAG_MFP: station uses management frame protection - */ -enum station_flags { - STATION_FLAG_CHANGED = 1<<0, - STATION_FLAG_AUTHORIZED = 1<<NL80211_STA_FLAG_AUTHORIZED, - STATION_FLAG_SHORT_PREAMBLE = 1<<NL80211_STA_FLAG_SHORT_PREAMBLE, - STATION_FLAG_WME = 1<<NL80211_STA_FLAG_WME, - STATION_FLAG_MFP = 1<<NL80211_STA_FLAG_MFP, -}; - -/** * enum plink_action - actions to perform in mesh peers * * @PLINK_ACTION_INVALID: action 0 is reserved @@ -294,14 +273,17 @@ enum plink_actions { * @supported_rates: supported rates in IEEE 802.11 format * (or NULL for no change) * @supported_rates_len: number of supported rates - * @station_flags: station flags (see &enum station_flags) + * @sta_flags_mask: station flags that changed + * (bitmask of BIT(NL80211_STA_FLAG_...)) + * @sta_flags_set: station flags values + * (bitmask of BIT(NL80211_STA_FLAG_...)) * @listen_interval: listen interval or -1 for no change * @aid: AID or zero for no change */ struct station_parameters { u8 *supported_rates; struct net_device *vlan; - u32 station_flags; + u32 sta_flags_mask, sta_flags_set; int listen_interval; u16 aid; u8 supported_rates_len; diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index be86e159e6e..d591a936f5c 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -629,34 +629,38 @@ static void sta_apply_parameters(struct ieee80211_local *local, int i, j; struct ieee80211_supported_band *sband; struct ieee80211_sub_if_data *sdata = sta->sdata; + u32 mask, set; sband = local->hw.wiphy->bands[local->oper_channel->band]; - /* - * FIXME: updating the flags is racy when this function is - * called from ieee80211_change_station(), this will - * be resolved in a future patch. - */ + spin_lock_bh(&sta->lock); + mask = params->sta_flags_mask; + set = params->sta_flags_set; - if (params->station_flags & STATION_FLAG_CHANGED) { - spin_lock_bh(&sta->lock); + if (mask & BIT(NL80211_STA_FLAG_AUTHORIZED)) { sta->flags &= ~WLAN_STA_AUTHORIZED; - if (params->station_flags & STATION_FLAG_AUTHORIZED) + if (set & BIT(NL80211_STA_FLAG_AUTHORIZED)) sta->flags |= WLAN_STA_AUTHORIZED; + } + if (mask & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) { sta->flags &= ~WLAN_STA_SHORT_PREAMBLE; - if (params->station_flags & STATION_FLAG_SHORT_PREAMBLE) + if (set & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) sta->flags |= WLAN_STA_SHORT_PREAMBLE; + } + if (mask & BIT(NL80211_STA_FLAG_WME)) { sta->flags &= ~WLAN_STA_WME; - if (params->station_flags & STATION_FLAG_WME) + if (set & BIT(NL80211_STA_FLAG_WME)) sta->flags |= WLAN_STA_WME; + } + if (mask & BIT(NL80211_STA_FLAG_MFP)) { sta->flags &= ~WLAN_STA_MFP; - if (params->station_flags & STATION_FLAG_MFP) + if (set & BIT(NL80211_STA_FLAG_MFP)) sta->flags |= WLAN_STA_MFP; - spin_unlock_bh(&sta->lock); } + spin_unlock_bh(&sta->lock); /* * FIXME: updating the following information is racy when this diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 2353ddbf493..66024ef57ba 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -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(); |