summaryrefslogtreecommitdiffstats
path: root/net/mac80211/cfg.c
diff options
context:
space:
mode:
authorJohannes Berg2011-12-14 12:35:30 +0100
committerJohn W. Linville2011-12-15 20:46:34 +0100
commitd9a7ddb05e5419ca5e4b54f57074dc33c7ea991c (patch)
tree3de3213e7e79a64254ea778374aeaaffa61b5bab /net/mac80211/cfg.c
parentmac80211: use station mutex in configuration (diff)
downloadkernel-qcow2-linux-d9a7ddb05e5419ca5e4b54f57074dc33c7ea991c.tar.gz
kernel-qcow2-linux-d9a7ddb05e5419ca5e4b54f57074dc33c7ea991c.tar.xz
kernel-qcow2-linux-d9a7ddb05e5419ca5e4b54f57074dc33c7ea991c.zip
mac80211: refactor station state transitions
Station entries can have various states, the most important ones being auth, assoc and authorized. This patch prepares us for telling the driver about these states, we don't want to confuse drivers with strange transitions, so with this we enforce that they move in the right order between them (back and forth); some transitions might happen before the driver even knows about the station, but at least runtime transitions will be ordered correctly. As a consequence, IBSS and MESH stations will now have the ASSOC flag set (so they can transition to AUTHORIZED), and we can get rid of a special case in TX processing. When freeing a station, unwind the state so that other parts of the code (or drivers later) can rely on the transitions. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/cfg.c')
-rw-r--r--net/mac80211/cfg.c76
1 files changed, 61 insertions, 15 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 3acda35df5cb..66ad9d9af87f 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -746,10 +746,11 @@ static void ieee80211_send_layer2_update(struct sta_info *sta)
netif_rx_ni(skb);
}
-static void sta_apply_parameters(struct ieee80211_local *local,
- struct sta_info *sta,
- struct station_parameters *params)
+static int sta_apply_parameters(struct ieee80211_local *local,
+ struct sta_info *sta,
+ struct station_parameters *params)
{
+ int ret = 0;
u32 rates;
int i, j;
struct ieee80211_supported_band *sband;
@@ -761,13 +762,59 @@ static void 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_checked(sta,
+ IEEE80211_STA_AUTH);
+ if (ret)
+ return ret;
+ ret = sta_info_move_state_checked(sta,
+ IEEE80211_STA_ASSOC);
+ if (ret)
+ return ret;
+ }
+ }
+
if (mask & BIT(NL80211_STA_FLAG_AUTHORIZED)) {
if (set & BIT(NL80211_STA_FLAG_AUTHORIZED))
- set_sta_flag(sta, WLAN_STA_AUTHORIZED);
+ ret = sta_info_move_state_checked(sta,
+ IEEE80211_STA_AUTHORIZED);
else
- clear_sta_flag(sta, WLAN_STA_AUTHORIZED);
+ ret = sta_info_move_state_checked(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_checked(sta,
+ IEEE80211_STA_AUTH);
+ if (ret)
+ return ret;
+ ret = sta_info_move_state_checked(sta,
+ IEEE80211_STA_NONE);
+ if (ret)
+ return ret;
+ }
+ }
+
+
if (mask & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) {
if (set & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE))
set_sta_flag(sta, WLAN_STA_SHORT_PREAMBLE);
@@ -792,13 +839,6 @@ static void sta_apply_parameters(struct ieee80211_local *local,
clear_sta_flag(sta, WLAN_STA_MFP);
}
- if (mask & BIT(NL80211_STA_FLAG_AUTHENTICATED)) {
- if (set & BIT(NL80211_STA_FLAG_AUTHENTICATED))
- set_sta_flag(sta, WLAN_STA_AUTH);
- else
- clear_sta_flag(sta, WLAN_STA_AUTH);
- }
-
if (mask & BIT(NL80211_STA_FLAG_TDLS_PEER)) {
if (set & BIT(NL80211_STA_FLAG_TDLS_PEER))
set_sta_flag(sta, WLAN_STA_TDLS_PEER);
@@ -870,6 +910,8 @@ static void sta_apply_parameters(struct ieee80211_local *local,
}
#endif
}
+
+ return 0;
}
static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
@@ -900,10 +942,14 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
if (!sta)
return -ENOMEM;
- set_sta_flag(sta, WLAN_STA_AUTH);
- set_sta_flag(sta, WLAN_STA_ASSOC);
+ sta_info_move_state(sta, IEEE80211_STA_AUTH);
+ sta_info_move_state(sta, IEEE80211_STA_ASSOC);
- sta_apply_parameters(local, sta, params);
+ err = sta_apply_parameters(local, sta, params);
+ if (err) {
+ sta_info_free(local, sta);
+ return err;
+ }
/*
* for TDLS, rate control should be initialized only when supported