aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/nl80211.h21
-rw-r--r--include/net/cfg80211.h28
-rw-r--r--net/mac80211/cfg.c28
-rw-r--r--net/wireless/nl80211.c38
4 files changed, 71 insertions, 44 deletions
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 58c4ee1822d3..aeefccfac0e1 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -25,6 +25,8 @@
25 * 25 *
26 */ 26 */
27 27
28#include <linux/types.h>
29
28/** 30/**
29 * DOC: Station handling 31 * DOC: Station handling
30 * 32 *
@@ -380,7 +382,7 @@ enum nl80211_commands {
380 * 382 *
381 * @NL80211_ATTR_STA_AID: Association ID for the station (u16) 383 * @NL80211_ATTR_STA_AID: Association ID for the station (u16)
382 * @NL80211_ATTR_STA_FLAGS: flags, nested element with NLA_FLAG attributes of 384 * @NL80211_ATTR_STA_FLAGS: flags, nested element with NLA_FLAG attributes of
383 * &enum nl80211_sta_flags. 385 * &enum nl80211_sta_flags (deprecated, use %NL80211_ATTR_STA_FLAGS2)
384 * @NL80211_ATTR_STA_LISTEN_INTERVAL: listen interval as defined by 386 * @NL80211_ATTR_STA_LISTEN_INTERVAL: listen interval as defined by
385 * IEEE 802.11 7.3.1.6 (u16). 387 * IEEE 802.11 7.3.1.6 (u16).
386 * @NL80211_ATTR_STA_SUPPORTED_RATES: supported rates, array of supported 388 * @NL80211_ATTR_STA_SUPPORTED_RATES: supported rates, array of supported
@@ -499,6 +501,9 @@ enum nl80211_commands {
499 * this attribute can be used 501 * this attribute can be used
500 * with %NL80211_CMD_ASSOCIATE request 502 * with %NL80211_CMD_ASSOCIATE request
501 * 503 *
504 * @NL80211_ATTR_STA_FLAGS2: Attribute containing a
505 * &struct nl80211_sta_flag_update.
506 *
502 * @NL80211_ATTR_MAX: highest attribute number currently defined 507 * @NL80211_ATTR_MAX: highest attribute number currently defined
503 * @__NL80211_ATTR_AFTER_LAST: internal use 508 * @__NL80211_ATTR_AFTER_LAST: internal use
504 */ 509 */
@@ -603,6 +608,8 @@ enum nl80211_attrs {
603 608
604 NL80211_ATTR_USE_MFP, 609 NL80211_ATTR_USE_MFP,
605 610
611 NL80211_ATTR_STA_FLAGS2,
612
606 /* add attributes here, update the policy in nl80211.c */ 613 /* add attributes here, update the policy in nl80211.c */
607 614
608 __NL80211_ATTR_AFTER_LAST, 615 __NL80211_ATTR_AFTER_LAST,
@@ -692,6 +699,18 @@ enum nl80211_sta_flags {
692}; 699};
693 700
694/** 701/**
702 * struct nl80211_sta_flag_update - station flags mask/set
703 * @mask: mask of station flags to set
704 * @set: which values to set them to
705 *
706 * Both mask and set contain bits as per &enum nl80211_sta_flags.
707 */
708struct nl80211_sta_flag_update {
709 __u32 mask;
710 __u32 set;
711} __attribute__((packed));
712
713/**
695 * enum nl80211_rate_info - bitrate information 714 * enum nl80211_rate_info - bitrate information
696 * 715 *
697 * These attribute types are used with %NL80211_STA_INFO_TXRATE 716 * These attribute types are used with %NL80211_STA_INFO_TXRATE
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index e69e6c66dd16..0dae6b382940 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -252,27 +252,6 @@ struct beacon_parameters {
252}; 252};
253 253
254/** 254/**
255 * enum station_flags - station flags
256 *
257 * Station capability flags. Note that these must be the bits
258 * according to the nl80211 flags.
259 *
260 * @STATION_FLAG_CHANGED: station flags were changed
261 * @STATION_FLAG_AUTHORIZED: station is authorized to send frames (802.1X)
262 * @STATION_FLAG_SHORT_PREAMBLE: station is capable of receiving frames
263 * with short preambles
264 * @STATION_FLAG_WME: station is WME/QoS capable
265 * @STATION_FLAG_MFP: station uses management frame protection
266 */
267enum station_flags {
268 STATION_FLAG_CHANGED = 1<<0,
269 STATION_FLAG_AUTHORIZED = 1<<NL80211_STA_FLAG_AUTHORIZED,
270 STATION_FLAG_SHORT_PREAMBLE = 1<<NL80211_STA_FLAG_SHORT_PREAMBLE,
271 STATION_FLAG_WME = 1<<NL80211_STA_FLAG_WME,
272 STATION_FLAG_MFP = 1<<NL80211_STA_FLAG_MFP,
273};
274
275/**
276 * enum plink_action - actions to perform in mesh peers 255 * enum plink_action - actions to perform in mesh peers
277 * 256 *
278 * @PLINK_ACTION_INVALID: action 0 is reserved 257 * @PLINK_ACTION_INVALID: action 0 is reserved
@@ -294,14 +273,17 @@ enum plink_actions {
294 * @supported_rates: supported rates in IEEE 802.11 format 273 * @supported_rates: supported rates in IEEE 802.11 format
295 * (or NULL for no change) 274 * (or NULL for no change)
296 * @supported_rates_len: number of supported rates 275 * @supported_rates_len: number of supported rates
297 * @station_flags: station flags (see &enum station_flags) 276 * @sta_flags_mask: station flags that changed
277 * (bitmask of BIT(NL80211_STA_FLAG_...))
278 * @sta_flags_set: station flags values
279 * (bitmask of BIT(NL80211_STA_FLAG_...))
298 * @listen_interval: listen interval or -1 for no change 280 * @listen_interval: listen interval or -1 for no change
299 * @aid: AID or zero for no change 281 * @aid: AID or zero for no change
300 */ 282 */
301struct station_parameters { 283struct station_parameters {
302 u8 *supported_rates; 284 u8 *supported_rates;
303 struct net_device *vlan; 285 struct net_device *vlan;
304 u32 station_flags; 286 u32 sta_flags_mask, sta_flags_set;
305 int listen_interval; 287 int listen_interval;
306 u16 aid; 288 u16 aid;
307 u8 supported_rates_len; 289 u8 supported_rates_len;
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index be86e159e6ef..d591a936f5c4 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -629,34 +629,38 @@ static void sta_apply_parameters(struct ieee80211_local *local,
629 int i, j; 629 int i, j;
630 struct ieee80211_supported_band *sband; 630 struct ieee80211_supported_band *sband;
631 struct ieee80211_sub_if_data *sdata = sta->sdata; 631 struct ieee80211_sub_if_data *sdata = sta->sdata;
632 u32 mask, set;
632 633
633 sband = local->hw.wiphy->bands[local->oper_channel->band]; 634 sband = local->hw.wiphy->bands[local->oper_channel->band];
634 635
635 /* 636 spin_lock_bh(&sta->lock);
636 * FIXME: updating the flags is racy when this function is 637 mask = params->sta_flags_mask;
637 * called from ieee80211_change_station(), this will 638 set = params->sta_flags_set;
638 * be resolved in a future patch.
639 */
640 639
641 if (params->station_flags & STATION_FLAG_CHANGED) { 640 if (mask & BIT(NL80211_STA_FLAG_AUTHORIZED)) {
642 spin_lock_bh(&sta->lock);
643 sta->flags &= ~WLAN_STA_AUTHORIZED; 641 sta->flags &= ~WLAN_STA_AUTHORIZED;
644 if (params->station_flags & STATION_FLAG_AUTHORIZED) 642 if (set & BIT(NL80211_STA_FLAG_AUTHORIZED))
645 sta->flags |= WLAN_STA_AUTHORIZED; 643 sta->flags |= WLAN_STA_AUTHORIZED;
644 }
646 645
646 if (mask & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) {
647 sta->flags &= ~WLAN_STA_SHORT_PREAMBLE; 647 sta->flags &= ~WLAN_STA_SHORT_PREAMBLE;
648 if (params->station_flags & STATION_FLAG_SHORT_PREAMBLE) 648 if (set & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE))
649 sta->flags |= WLAN_STA_SHORT_PREAMBLE; 649 sta->flags |= WLAN_STA_SHORT_PREAMBLE;
650 }
650 651
652 if (mask & BIT(NL80211_STA_FLAG_WME)) {
651 sta->flags &= ~WLAN_STA_WME; 653 sta->flags &= ~WLAN_STA_WME;
652 if (params->station_flags & STATION_FLAG_WME) 654 if (set & BIT(NL80211_STA_FLAG_WME))
653 sta->flags |= WLAN_STA_WME; 655 sta->flags |= WLAN_STA_WME;
656 }
654 657
658 if (mask & BIT(NL80211_STA_FLAG_MFP)) {
655 sta->flags &= ~WLAN_STA_MFP; 659 sta->flags &= ~WLAN_STA_MFP;
656 if (params->station_flags & STATION_FLAG_MFP) 660 if (set & BIT(NL80211_STA_FLAG_MFP))
657 sta->flags |= WLAN_STA_MFP; 661 sta->flags |= WLAN_STA_MFP;
658 spin_unlock_bh(&sta->lock);
659 } 662 }
663 spin_unlock_bh(&sta->lock);
660 664
661 /* 665 /*
662 * FIXME: updating the following information is racy when this 666 * FIXME: updating the following information is racy when this
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 2353ddbf4934..66024ef57bab 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 = {
123 [NL80211_ATTR_FREQ_FIXED] = { .type = NLA_FLAG }, 123 [NL80211_ATTR_FREQ_FIXED] = { .type = NLA_FLAG },
124 [NL80211_ATTR_TIMED_OUT] = { .type = NLA_FLAG }, 124 [NL80211_ATTR_TIMED_OUT] = { .type = NLA_FLAG },
125 [NL80211_ATTR_USE_MFP] = { .type = NLA_U32 }, 125 [NL80211_ATTR_USE_MFP] = { .type = NLA_U32 },
126 [NL80211_ATTR_STA_FLAGS2] = {
127 .len = sizeof(struct nl80211_sta_flag_update),
128 },
126}; 129};
127 130
128/* IE validation */ 131/* IE validation */
@@ -1334,13 +1337,33 @@ static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = {
1334 [NL80211_STA_FLAG_MFP] = { .type = NLA_FLAG }, 1337 [NL80211_STA_FLAG_MFP] = { .type = NLA_FLAG },
1335}; 1338};
1336 1339
1337static int parse_station_flags(struct nlattr *nla, u32 *staflags) 1340static int parse_station_flags(struct genl_info *info,
1341 struct station_parameters *params)
1338{ 1342{
1339 struct nlattr *flags[NL80211_STA_FLAG_MAX + 1]; 1343 struct nlattr *flags[NL80211_STA_FLAG_MAX + 1];
1344 struct nlattr *nla;
1340 int flag; 1345 int flag;
1341 1346
1342 *staflags = 0; 1347 /*
1348 * Try parsing the new attribute first so userspace
1349 * can specify both for older kernels.
1350 */
1351 nla = info->attrs[NL80211_ATTR_STA_FLAGS2];
1352 if (nla) {
1353 struct nl80211_sta_flag_update *sta_flags;
1354
1355 sta_flags = nla_data(nla);
1356 params->sta_flags_mask = sta_flags->mask;
1357 params->sta_flags_set = sta_flags->set;
1358 if ((params->sta_flags_mask |
1359 params->sta_flags_set) & BIT(__NL80211_STA_FLAG_INVALID))
1360 return -EINVAL;
1361 return 0;
1362 }
1363
1364 /* if present, parse the old attribute */
1343 1365
1366 nla = info->attrs[NL80211_ATTR_STA_FLAGS];
1344 if (!nla) 1367 if (!nla)
1345 return 0; 1368 return 0;
1346 1369
@@ -1348,11 +1371,12 @@ static int parse_station_flags(struct nlattr *nla, u32 *staflags)
1348 nla, sta_flags_policy)) 1371 nla, sta_flags_policy))
1349 return -EINVAL; 1372 return -EINVAL;
1350 1373
1351 *staflags = STATION_FLAG_CHANGED; 1374 params->sta_flags_mask = (1 << __NL80211_STA_FLAG_AFTER_LAST) - 1;
1375 params->sta_flags_mask &= ~1;
1352 1376
1353 for (flag = 1; flag <= NL80211_STA_FLAG_MAX; flag++) 1377 for (flag = 1; flag <= NL80211_STA_FLAG_MAX; flag++)
1354 if (flags[flag]) 1378 if (flags[flag])
1355 *staflags |= (1<<flag); 1379 params->sta_flags_set |= (1<<flag);
1356 1380
1357 return 0; 1381 return 0;
1358} 1382}
@@ -1648,8 +1672,7 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
1648 params.ht_capa = 1672 params.ht_capa =
1649 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); 1673 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]);
1650 1674
1651 if (parse_station_flags(info->attrs[NL80211_ATTR_STA_FLAGS], 1675 if (parse_station_flags(info, &params))
1652 &params.station_flags))
1653 return -EINVAL; 1676 return -EINVAL;
1654 1677
1655 if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION]) 1678 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)
1718 params.ht_capa = 1741 params.ht_capa =
1719 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); 1742 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]);
1720 1743
1721 if (parse_station_flags(info->attrs[NL80211_ATTR_STA_FLAGS], 1744 if (parse_station_flags(info, &params))
1722 &params.station_flags))
1723 return -EINVAL; 1745 return -EINVAL;
1724 1746
1725 rtnl_lock(); 1747 rtnl_lock();