summaryrefslogtreecommitdiff
path: root/net/mac80211/cfg.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/cfg.c')
-rw-r--r--net/mac80211/cfg.c115
1 files changed, 71 insertions, 44 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 3e7d557fd481..f4d12c71928d 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -510,6 +510,7 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
BIT(NL80211_STA_FLAG_WME) |
BIT(NL80211_STA_FLAG_MFP) |
BIT(NL80211_STA_FLAG_AUTHENTICATED) |
+ BIT(NL80211_STA_FLAG_ASSOCIATED) |
BIT(NL80211_STA_FLAG_TDLS_PEER);
if (test_sta_flag(sta, WLAN_STA_AUTHORIZED))
sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_AUTHORIZED);
@@ -521,6 +522,8 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_MFP);
if (test_sta_flag(sta, WLAN_STA_AUTH))
sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_AUTHENTICATED);
+ if (test_sta_flag(sta, WLAN_STA_ASSOC))
+ sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_ASSOCIATED);
if (test_sta_flag(sta, WLAN_STA_TDLS_PEER))
sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER);
}
@@ -1077,6 +1080,58 @@ static void ieee80211_send_layer2_update(struct sta_info *sta)
netif_rx_ni(skb);
}
+static int sta_apply_auth_flags(struct ieee80211_local *local,
+ struct sta_info *sta,
+ u32 mask, u32 set)
+{
+ int ret;
+
+ if (mask & BIT(NL80211_STA_FLAG_AUTHENTICATED) &&
+ set & BIT(NL80211_STA_FLAG_AUTHENTICATED) &&
+ !test_sta_flag(sta, WLAN_STA_AUTH)) {
+ ret = sta_info_move_state(sta, IEEE80211_STA_AUTH);
+ if (ret)
+ return ret;
+ }
+
+ if (mask & BIT(NL80211_STA_FLAG_ASSOCIATED) &&
+ set & BIT(NL80211_STA_FLAG_ASSOCIATED) &&
+ !test_sta_flag(sta, WLAN_STA_ASSOC)) {
+ ret = sta_info_move_state(sta, IEEE80211_STA_ASSOC);
+ if (ret)
+ return ret;
+ }
+
+ if (mask & BIT(NL80211_STA_FLAG_AUTHORIZED)) {
+ if (set & BIT(NL80211_STA_FLAG_AUTHORIZED))
+ ret = sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED);
+ else if (test_sta_flag(sta, WLAN_STA_AUTHORIZED))
+ ret = sta_info_move_state(sta, IEEE80211_STA_ASSOC);
+ else
+ ret = 0;
+ if (ret)
+ return ret;
+ }
+
+ if (mask & BIT(NL80211_STA_FLAG_ASSOCIATED) &&
+ !(set & BIT(NL80211_STA_FLAG_ASSOCIATED)) &&
+ test_sta_flag(sta, WLAN_STA_ASSOC)) {
+ ret = sta_info_move_state(sta, IEEE80211_STA_AUTH);
+ if (ret)
+ return ret;
+ }
+
+ if (mask & BIT(NL80211_STA_FLAG_AUTHENTICATED) &&
+ !(set & BIT(NL80211_STA_FLAG_AUTHENTICATED)) &&
+ test_sta_flag(sta, WLAN_STA_AUTH)) {
+ ret = sta_info_move_state(sta, IEEE80211_STA_NONE);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
static int sta_apply_parameters(struct ieee80211_local *local,
struct sta_info *sta,
struct station_parameters *params)
@@ -1094,52 +1149,20 @@ static int sta_apply_parameters(struct ieee80211_local *local,
mask = params->sta_flags_mask;
set = params->sta_flags_set;
- /*
- * In mesh mode, we can clear AUTHENTICATED flag but must
- * also make ASSOCIATED follow appropriately for the driver
- * API. See also below, after AUTHORIZED changes.
- */
- if (mask & BIT(NL80211_STA_FLAG_AUTHENTICATED)) {
- /* cfg80211 should not allow this in non-mesh modes */
- if (WARN_ON(!ieee80211_vif_is_mesh(&sdata->vif)))
- return -EINVAL;
-
- if (set & BIT(NL80211_STA_FLAG_AUTHENTICATED) &&
- !test_sta_flag(sta, WLAN_STA_AUTH)) {
- ret = sta_info_move_state(sta, IEEE80211_STA_AUTH);
- if (ret)
- return ret;
- ret = sta_info_move_state(sta, IEEE80211_STA_ASSOC);
- if (ret)
- return ret;
- }
- }
-
- if (mask & BIT(NL80211_STA_FLAG_AUTHORIZED)) {
- if (set & BIT(NL80211_STA_FLAG_AUTHORIZED))
- ret = sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED);
- else if (test_sta_flag(sta, WLAN_STA_AUTHORIZED))
- ret = sta_info_move_state(sta, IEEE80211_STA_ASSOC);
- if (ret)
- return ret;
- }
-
- if (mask & BIT(NL80211_STA_FLAG_AUTHENTICATED)) {
- /* cfg80211 should not allow this in non-mesh modes */
- if (WARN_ON(!ieee80211_vif_is_mesh(&sdata->vif)))
- return -EINVAL;
-
- if (!(set & BIT(NL80211_STA_FLAG_AUTHENTICATED)) &&
- test_sta_flag(sta, WLAN_STA_AUTH)) {
- ret = sta_info_move_state(sta, IEEE80211_STA_AUTH);
- if (ret)
- return ret;
- ret = sta_info_move_state(sta, IEEE80211_STA_NONE);
- if (ret)
- return ret;
- }
+ if (ieee80211_vif_is_mesh(&sdata->vif)) {
+ /*
+ * In mesh mode, ASSOCIATED isn't part of the nl80211
+ * API but must follow AUTHENTICATED for driver state.
+ */
+ if (mask & BIT(NL80211_STA_FLAG_AUTHENTICATED))
+ mask |= BIT(NL80211_STA_FLAG_ASSOCIATED);
+ if (set & BIT(NL80211_STA_FLAG_AUTHENTICATED))
+ set |= BIT(NL80211_STA_FLAG_ASSOCIATED);
}
+ ret = sta_apply_auth_flags(local, sta, mask, set);
+ if (ret)
+ return ret;
if (mask & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) {
if (set & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE))
@@ -1273,6 +1296,10 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
if (!sta)
return -ENOMEM;
+ /*
+ * defaults -- if userspace wants something else we'll
+ * change it accordingly in sta_apply_parameters()
+ */
sta_info_pre_move_state(sta, IEEE80211_STA_AUTH);
sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC);