refactor station state management
Johannes Berg
maintainercover refactor station state management
Here's a first step towards something I talked to some of you about -- making drivers more aware of station state.
Because experience tells me that drivers will be written for the common case, and forget about uncommon sequences, this first step enforces proper ordering of states, now a station can move only between these states like this:
NONE <--> AUTHENTICATED <--> ASSOCIATED <--> AUTHORIZED
As a consequence, IBSS stations and WDS peers need to go through ASSOCIATED state (and get ASSOC flag set), but this doesn't seem to be an issue, in fact it makes at least one place in the code simpler.
This patchset still has two issues:
* secure mesh is broken right now I think, its state change possibilities are rather confusing (need help to fix this, at least explanations)
* TLDS isn't handled (maybe not an issue?)
My further plan is the following:
1) figure out the issues above
2) notify drivers of these state changes
3) refactor auth/assoc process as described before
a) don't track multiple authentications
b) don't try to keep an existing authentication/association
c) set channel first etc.
4) remove dummy station code
a) add regular station entry before auth
b) notify to AUTH state when auth succeeds
c) notify to ASSOC state when assoc succeeds
This patchset is but the first step on this journey, at the end of which we will hopefully find multi-channel support :-)
johannes
Johannes Berg
maintainerRFC 1/4 mac80211: use station mutex in configuration
From: Johannes Berg <[email protected]>
There's no need to use RCU here, we can just lock
the station mutex instead. This allows the code
to sleep, which is necessary for later patches.
--- net/mac80211/cfg.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
net/mac80211/cfg.c +6 -6
@@ -960,11 +960,11 @@ static int ieee80211_change_station(strustruct sta_info *sta;struct ieee80211_sub_if_data *vlansdata; -rcu_read_lock (); +mutex_lock (&local->sta_mtx); sta =sta_info_get_bss (sdata, mac);if (!sta) { -rcu_read_unlock (); +mutex_unlock (&local->sta_mtx);return -ENOENT ; }
@@ -972,7 +972,7 @@ static int ieee80211_change_station(struif ((params->sta_flags_mask &BIT (NL80211_STA_FLAG_TDLS_PEER )) && !!(params->sta_flags_set &BIT (NL80211_STA_FLAG_TDLS_PEER )) != !!test_sta_flag (sta,WLAN_STA_TDLS_PEER )) { -rcu_read_unlock (); +mutex_unlock (&local->sta_mtx);return -EINVAL ; }
@@ -981,13 +981,13 @@ static int ieee80211_change_station(struif (vlansdata->vif.type !=NL80211_IFTYPE_AP_VLAN && vlansdata->vif.type !=NL80211_IFTYPE_AP ) { -rcu_read_unlock (); +mutex_unlock (&local->sta_mtx);return -EINVAL ; }if (params->vlan->ieee80211_ptr->use_4addr) {if (vlansdata->u.vlan.sta) { -rcu_read_unlock (); +mutex_unlock (&local->sta_mtx);return -EBUSY ; }
@@ -1003,7 +1003,7 @@ static int ieee80211_change_station(struif (test_sta_flag (sta,WLAN_STA_TDLS_PEER ) && params->supported_rates)rate_control_rate_init (sta); -rcu_read_unlock (); +mutex_unlock (&local->sta_mtx);if (sdata->vif.type ==NL80211_IFTYPE_STATION && params->sta_flags_mask &BIT (NL80211_STA_FLAG_AUTHORIZED ))
Johannes Berg
maintainerRFC 2/4 mac80211: refactor station state transitions
In reply to Johannes BergFrom: Johannes Berg <[email protected]>
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.
TBD: WLAN_STA_TDLS_PEER_AUTH?
TBD: secure mesh AUTH transitions?
--- net/mac80211/cfg.c | 44 +++++++++++++++++++++----------- net/mac80211/ibss.c | 5 ++- net/mac80211/iface.c | 5 ++- net/mac80211/mesh_plink.c | 7 +++-- net/mac80211/mlme.c | 6 ++-- net/mac80211/sta_info.c | 62 +++++++++++++++++++++++++++++++++++++++++----- net/mac80211/sta_info.h | 36 ++++++++++++++++++++++++++ net/mac80211/tx.c | 1 8 files changed, 136 insertions(+), 30 deletions(-)
net/mac80211/sta_info.c +56 -6
@@ -204,16 +204,17 @@ struct sta_info *sta_info_get_by_idx(str }/** -* __sta_info_free - internal STA free helper +* sta_info_free - free STA * * @local: pointer to the global information * @sta: STA info to free * * This function must undo everything done by sta_info_alloc() -* that may happen before sta_info_insert(). +* that may happen before sta_info_insert(). It may only be +* called when sta_info_insert() has not been attempted (and +* if that fails, the station is freed anyway.) */ -static void __sta_info_free (struct ieee80211_local *local, -struct sta_info *sta) +void sta_info_free (struct ieee80211_local *local,struct sta_info *sta) {if (sta->rate_ctrl) {rate_control_free_sta (sta);
@@ -598,7 +599,7 @@ int sta_info_insert_rcu(struct sta_inforeturn 0 ; out_free:BUG_ON (!err); -__sta_info_free (local, sta); +sta_info_free (local, sta);return err; }
@@ -949,7 +950,7 @@ static int __must_check __sta_info_destr }#endif -__sta_info_free (local, sta); +sta_info_free (local, sta);return 0 ; }
@@ -1513,3 +1514,52 @@ void ieee80211_sta_set_buffered(struct ista_info_recalc_tim (sta); }EXPORT_SYMBOL (ieee80211_sta_set_buffered); + +int sta_info_move_state_checked (struct sta_info *sta, +enum ieee80211_sta_state new_state) +{ +might_sleep ();/* for driver notify later */ + +if (sta->sta_state == new_state) +return 0 ; + +switch (new_state) { +case IEEE80211_STA_NONE : +if (sta->sta_state ==IEEE80211_STA_AUTH ) +clear_bit (WLAN_STA_AUTH , &sta->_flags); +else +return -EINVAL ; +break ; +case IEEE80211_STA_AUTH : +if (sta->sta_state ==IEEE80211_STA_NONE ) +set_bit (WLAN_STA_AUTH , &sta->_flags); +else if (sta->sta_state ==IEEE80211_STA_ASSOC ) +clear_bit (WLAN_STA_ASSOC , &sta->_flags); +else +return -EINVAL ; +break ; +case IEEE80211_STA_ASSOC : +if (sta->sta_state ==IEEE80211_STA_AUTH ) +set_bit (WLAN_STA_ASSOC , &sta->_flags); +else if (sta->sta_state ==IEEE80211_STA_AUTHORIZED ) +clear_bit (WLAN_STA_AUTHORIZED , &sta->_flags); +else +return -EINVAL ; +break ; +case IEEE80211_STA_AUTHORIZED : +if (sta->sta_state ==IEEE80211_STA_ASSOC ) +set_bit (WLAN_STA_AUTHORIZED , &sta->_flags); +else +return -EINVAL ; +break ; +default : +WARN (1 ,"invalid state %d" , new_state); +return -EINVAL ; + } + +printk (KERN_DEBUG "%s: moving STA %pM to state %d\n" , + sta->sdata->name, sta->sta.addr, new_state); + sta->sta_state = new_state; + +return 0 ; +}
net/mac80211/sta_info.h +36 -0
@@ -73,6 +73,13 @@ enum ieee80211_sta_info_flags { WLAN_STA_4ADDR_EVENT, }; +enum ieee80211_sta_state { +IEEE80211_STA_NONE , +IEEE80211_STA_AUTH , +IEEE80211_STA_ASSOC , +IEEE80211_STA_AUTHORIZED , +}; +#define STA_TID_NUM 16#define ADDBA_RESP_INTERVAL HZ#define HT_AGG_MAX_RETRIES 0x3
@@ -262,6 +269,7 @@ struct sta_ampdu_mlme {* @dummy: indicate a dummy station created for receiving * EAP frames before association * @sta: station information we share with the driver +* @sta_state: duplicates information about station state (for debug) */ struct sta_info {/* General information, mostly static */
@@ -283,6 +291,8 @@ struct sta_info {bool uploaded; +enum ieee80211_sta_state sta_state; +/* use the accessors defined below */ unsigned long _flags;
@@ -371,12 +381,18 @@ static inline enum nl80211_plink_state sstatic inline void set_sta_flag (struct sta_info *sta,enum ieee80211_sta_info_flags flag) { +WARN_ON (flag ==WLAN_STA_AUTH || + flag ==WLAN_STA_ASSOC || + flag ==WLAN_STA_AUTHORIZED );set_bit (flag, &sta->_flags); }static inline void clear_sta_flag (struct sta_info *sta,enum ieee80211_sta_info_flags flag) { +WARN_ON (flag ==WLAN_STA_AUTH || + flag ==WLAN_STA_ASSOC || + flag ==WLAN_STA_AUTHORIZED );clear_bit (flag, &sta->_flags); }
@@ -389,15 +405,32 @@ static inline int test_sta_flag(struct sstatic inline int test_and_clear_sta_flag (struct sta_info *sta,enum ieee80211_sta_info_flags flag) { +WARN_ON (flag ==WLAN_STA_AUTH || + flag ==WLAN_STA_ASSOC || + flag ==WLAN_STA_AUTHORIZED );return test_and_clear_bit (flag, &sta->_flags); }static inline int test_and_set_sta_flag (struct sta_info *sta,enum ieee80211_sta_info_flags flag) { +WARN_ON (flag ==WLAN_STA_AUTH || + flag ==WLAN_STA_ASSOC || + flag ==WLAN_STA_AUTHORIZED );return test_and_set_bit (flag, &sta->_flags); } +int sta_info_move_state_checked (struct sta_info *sta, +enum ieee80211_sta_state new_state); + +static inline void sta_info_move_state (struct sta_info *sta, +enum ieee80211_sta_state new_state) +{ +int ret =sta_info_move_state_checked (sta, new_state); +WARN_ON_ONCE (ret); +} + +void ieee80211_assign_tid_tx (struct sta_info *sta,int tid,struct tid_ampdu_tx *tid_tx);
@@ -489,6 +522,9 @@ struct sta_info *sta_info_get_by_idx(str*/ struct sta_info *sta_info_alloc (struct ieee80211_sub_if_data *sdata,u8 *addr,gfp_t gfp); + +void sta_info_free (struct ieee80211_local *local,struct sta_info *sta); +/* * Insert STA info into hash table/list, returns zero or a * -EEXIST if (if the same MAC address is already present).
net/mac80211/cfg.c +29 -15
79 lines not on this page · raw message
net/mac80211/ibss.c +4 -1
@@ -512,7 +512,10 @@ struct sta_info *ieee80211_ibss_add_sta(return NULL ; sta->last_rx = jiffies; -set_sta_flag (sta,WLAN_STA_AUTHORIZED ); + +sta_info_move_state (sta,IEEE80211_STA_AUTH ); +sta_info_move_state (sta,IEEE80211_STA_ASSOC ); +sta_info_move_state (sta,IEEE80211_STA_AUTHORIZED );/* make sure mandatory rates are always added */ sta->sta.supp_rates[band] = supp_rates |
net/mac80211/iface.c +3 -2
@@ -318,8 +318,9 @@ static int ieee80211_do_open(struct net_ goto err_del_interface; } -/* no atomic bitop required since STA is not live yet */ -set_sta_flag (sta,WLAN_STA_AUTHORIZED ); +sta_info_move_state (sta,IEEE80211_STA_AUTH ); +sta_info_move_state (sta,IEEE80211_STA_ASSOC ); +sta_info_move_state (sta,IEEE80211_STA_AUTHORIZED ); res =sta_info_insert (sta);if (res) {
net/mac80211/mesh_plink.c +5 -2
@@ -96,9 +96,12 @@ static struct sta_info *mesh_plink_allocif (!sta)return NULL ; -set_sta_flag (sta,WLAN_STA_AUTH ); -set_sta_flag (sta,WLAN_STA_AUTHORIZED ); +sta_info_move_state (sta,IEEE80211_STA_AUTH ); +sta_info_move_state (sta,IEEE80211_STA_ASSOC ); +sta_info_move_state (sta,IEEE80211_STA_AUTHORIZED ); +set_sta_flag (sta,WLAN_STA_WME ); + sta->sta.supp_rates[local->hw.conf.channel->band] = rates;if (elems->ht_cap_elem) ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
net/mac80211/mlme.c +3 -3
@@ -1577,10 +1577,10 @@ static bool ieee80211_assoc_success(strureturn false; } -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 );if (!(ifmgd->flags &IEEE80211_STA_CONTROL_PORT )) -set_sta_flag (sta,WLAN_STA_AUTHORIZED ); +sta_info_move_state (sta,IEEE80211_STA_AUTHORIZED ); rates =0 ; basic_rates =0 ;
net/mac80211/tx.c +0 -1
@@ -295,7 +295,6 @@ ieee80211_tx_h_check_assoc(struct ieee80if (likely (tx->flags &IEEE80211_TX_UNICAST )) {if (unlikely (!assoc && - tx->sdata->vif.type !=NL80211_IFTYPE_ADHOC &&ieee80211_is_data (hdr->frame_control))) {#ifdef CONFIG_MAC80211_VERBOSE_DEBUG printk(KERN_DEBUG "%s: dropped data frame to not "
Re: [RFC 2/4] mac80211: refactor station state transitions
Quoted 12 lines · Johannes Berg
From: Johannes Berg <[email protected]>
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.
Quoted 7 lines
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.
TBD:
WLAN_STA_TDLS_PEER_AUTH?
TBD: secure mesh AUTH transitions?
This patch makes it impossible to add a new unauthenticated station, AFAICT. Maybe this is not even desirable from mac80211's POV? The reason the secure mesh daemon adds a new unauthenticated peer is to stop NL80211_NEW_PEER_CANDIDATE notifications while userspace is handling the authentication process, and we need a station entry for ieee80211_mgmt_tx().
Some other mechanism could be implemented to halt new peer notifications, or just allow userspace to add a station in state NONE (ieee80211_tx_h_check_assoc() doesn't even check association flag for mesh interfaces).
Thomas
Quoted 366 lines
Signed-off-by Johannes Berg <[email protected]>---
net/mac80211/cfg.c | 44 +++++++++++++++++++++-----------net/mac80211/ibss.c| 5 ++-
net/mac80211/iface.c | 5 ++-
net/mac80211/mesh_plink.c | 7 +++--
net/mac80211/mlme.c | 6 ++--
net/mac80211/sta_info.c | 62 +++++++++++++++++++++++++++++++++++++++++-----net/mac80211/sta_info.h| 36 ++++++++++++++++++++++++++net/mac80211/tx.c| 18 files changed, 136 insertions(+), 30 deletions(-)net/mac80211/sta_info.c 2011-12-13 21:03:19.000000000 +0100 renamed from net/mac80211/sta_info.c 2011-12-13 21:01:26.000000000 +0100 +5
-4@@ -204,16 +204,17 @@ struct sta_info *sta_info_get_by_idx(str } /** - * __sta_info_free - internal STA free helper + * sta_info_free - free STA * * @local: pointer to the global information * @sta: STA info to free * * This function must undo everything done by sta_info_alloc() - * that may happen before sta_info_insert(). + * that may happen before sta_info_insert(). It may only be + * called when sta_info_insert() has not been attempted (and + * if that fails, the station is freed anyway.) */ -static void __sta_info_free(struct ieee80211_local *local, - struct sta_info *sta) +void sta_info_free(struct ieee80211_local *local, struct sta_info *sta) { if (sta->rate_ctrl) { rate_control_free_sta(sta);@@ -598,7 +599,7 @@ int sta_info_insert_rcu(struct sta_info return 0;out_free:
BUG_ON(!err);
-__sta_info_free(local, sta);
+sta_info_free(local, sta);
return err;
}net/mac80211/sta_info.c 2011-12-13 21:03:19.000000000 +0100 renamed from net/mac80211/sta_info.c 2011-12-13 21:01:26.000000000 +0100 +50
-1@@ -949,7 +950,7 @@ static int __must_check __sta_info_destr } #endif - __sta_info_free(local, sta); + sta_info_free(local, sta); return 0; }@@ -1513,3 +1514,52 @@ void ieee80211_sta_set_buffered(struct i sta_info_recalc_tim(sta); } EXPORT_SYMBOL(ieee80211_sta_set_buffered); + +int sta_info_move_state_checked(struct sta_info *sta, + enum ieee80211_sta_state new_state) +{ + might_sleep(); /* for driver notify later */ + + if (sta->sta_state == new_state) + return 0; + + switch (new_state) { + case IEEE80211_STA_NONE: + if (sta->sta_state == IEEE80211_STA_AUTH) + clear_bit(WLAN_STA_AUTH, &sta->_flags); + else + return -EINVAL; + break; + case IEEE80211_STA_AUTH: + if (sta->sta_state == IEEE80211_STA_NONE) + set_bit(WLAN_STA_AUTH, &sta->_flags); + else if (sta->sta_state == IEEE80211_STA_ASSOC) + clear_bit(WLAN_STA_ASSOC, &sta->_flags); + else + return -EINVAL; + break; + case IEEE80211_STA_ASSOC: + if (sta->sta_state == IEEE80211_STA_AUTH) + set_bit(WLAN_STA_ASSOC, &sta->_flags); + else if (sta->sta_state == IEEE80211_STA_AUTHORIZED) + clear_bit(WLAN_STA_AUTHORIZED, &sta->_flags); + else + return -EINVAL; + break; + case IEEE80211_STA_AUTHORIZED: + if (sta->sta_state == IEEE80211_STA_ASSOC) + set_bit(WLAN_STA_AUTHORIZED, &sta->_flags); + else + return -EINVAL; + break; + default: + WARN(1, "invalid state %d", new_state); + return -EINVAL; + } + + printk(KERN_DEBUG "%s: moving STA %pM to state %d\n", + sta->sdata->name, sta->sta.addr, new_state); + sta->sta_state = new_state; + + return 0; +}net/mac80211/sta_info.h 2011-12-13 21:03:10.000000000 +0100 renamed from net/mac80211/sta_info.h 2011-12-13 21:01:26.000000000 +0100 +36
-0@@ -73,6 +73,13 @@ enum ieee80211_sta_info_flags { WLAN_STA_4ADDR_EVENT, }; +enum ieee80211_sta_state { + IEEE80211_STA_NONE, + IEEE80211_STA_AUTH, + IEEE80211_STA_ASSOC, + IEEE80211_STA_AUTHORIZED, +}; + #define STA_TID_NUM 16 #define ADDBA_RESP_INTERVAL HZ #define HT_AGG_MAX_RETRIES 0x3@@ -262,6 +269,7 @@ struct sta_ampdu_mlme { * @dummy: indicate a dummy station created for receiving * EAP frames before association * @sta: station information we share with the driver + * @sta_state: duplicates information about station state (for debug) */ struct sta_info { /* General information, mostly static */@@ -283,6 +291,8 @@ struct sta_info { bool uploaded; + enum ieee80211_sta_state sta_state; + /* use the accessors defined below */ unsigned long _flags;@@ -371,12 +381,18 @@ static inline enum nl80211_plink_state s static inline void set_sta_flag(struct sta_info *sta, enum ieee80211_sta_info_flags flag) { + WARN_ON(flag == WLAN_STA_AUTH || + flag == WLAN_STA_ASSOC || + flag == WLAN_STA_AUTHORIZED); set_bit(flag, &sta->_flags); } static inline void clear_sta_flag(struct sta_info *sta, enum ieee80211_sta_info_flags flag) { + WARN_ON(flag == WLAN_STA_AUTH || + flag == WLAN_STA_ASSOC || + flag == WLAN_STA_AUTHORIZED); clear_bit(flag, &sta->_flags); }@@ -389,15 +405,32 @@ static inline int test_sta_flag(struct s static inline int test_and_clear_sta_flag(struct sta_info *sta, enum ieee80211_sta_info_flags flag) { + WARN_ON(flag == WLAN_STA_AUTH || + flag == WLAN_STA_ASSOC || + flag == WLAN_STA_AUTHORIZED); return test_and_clear_bit(flag, &sta->_flags); } static inline int test_and_set_sta_flag(struct sta_info *sta, enum ieee80211_sta_info_flags flag) { + WARN_ON(flag == WLAN_STA_AUTH || + flag == WLAN_STA_ASSOC || + flag == WLAN_STA_AUTHORIZED); return test_and_set_bit(flag, &sta->_flags); } +int sta_info_move_state_checked(struct sta_info *sta, + enum ieee80211_sta_state new_state); + +static inline void sta_info_move_state(struct sta_info *sta, + enum ieee80211_sta_state new_state) +{ + int ret = sta_info_move_state_checked(sta, new_state); + WARN_ON_ONCE(ret); +} + + void ieee80211_assign_tid_tx(struct sta_info *sta, int tid, struct tid_ampdu_tx *tid_tx);@@ -489,6 +522,9 @@ struct sta_info *sta_info_get_by_idx(str */ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, u8 *addr, gfp_t gfp); + +void sta_info_free(struct ieee80211_local *local, struct sta_info *sta); + /* * Insert STA info into hash table/list, returns zero or a * -EEXIST if (if the same MAC address is already present).net/mac80211/cfg.c 2011-12-13 21:03:10.000000000 +0100 renamed from net/mac80211/cfg.c 2011-12-13 21:01:28.000000000 +0100 +6
-4@@ -746,10 +746,11 @@ static void ieee80211_send_layer2_update 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;@@ -763,11 +764,25 @@ static void sta_apply_parameters(struct 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 (mask &
BIT(NL80211_STA_FLAG_AUTHENTICATED)) {
+ if (set &BIT(NL80211_STA_FLAG_AUTHENTICATED))
+ ret = sta_info_move_state_checked(sta,
+IEEE80211_STA_AUTH);
+ else
+ ret = sta_info_move_state_checked(sta,
+IEEE80211_STA_NONE);
+ }net/mac80211/cfg.c 2011-12-13 21:03:10.000000000 +0100 renamed from net/mac80211/cfg.c 2011-12-13 21:01:28.000000000 +0100 +4
-0+ + 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);net/mac80211/cfg.c 2011-12-13 21:03:10.000000000 +0100 renamed from net/mac80211/cfg.c 2011-12-13 21:01:28.000000000 +0100 +9
-10@@ -792,13 +807,6 @@ static void sta_apply_parameters(struct 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 +878,8 @@ static void sta_apply_parameters(struct } #endif } + + return 0; } static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,@@ -906,10 +916,14 @@ static int ieee80211_add_station(struct 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 supportednet/mac80211/ibss.c 2011-12-13 21:03:10.000000000 +0100 renamed from net/mac80211/ibss.c 2011-12-13 21:01:26.000000000 +0100 +4
-1@@ -512,7 +512,10 @@ struct sta_info *ieee80211_ibss_add_sta( return NULL; sta->last_rx = jiffies; - set_sta_flag(sta, WLAN_STA_AUTHORIZED); + + sta_info_move_state(sta, IEEE80211_STA_AUTH); + sta_info_move_state(sta, IEEE80211_STA_ASSOC); + sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED); /* make sure mandatory rates are always added */sta->sta.supp_rates[band] =
supp_rates|net/mac80211/iface.c 2011-12-13 21:03:10.000000000 +0100 renamed from net/mac80211/iface.c 2011-12-13 21:01:26.000000000 +0100 +3
-2@@ -318,8 +318,9 @@ static int ieee80211_do_open(struct net_ goto err_del_interface; } - /* no atomic bitop required since STA is not live yet */ - set_sta_flag(sta, WLAN_STA_AUTHORIZED); + sta_info_move_state(sta, IEEE80211_STA_AUTH); + sta_info_move_state(sta, IEEE80211_STA_ASSOC); + sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED); res = sta_info_insert(sta); if (res) {net/mac80211/mesh_plink.c 2011-12-13 21:03:10.000000000 +0100 renamed from net/mac80211/mesh_plink.c 2011-12-13 21:01:26.000000000 +0100 +5
-2@@ -96,9 +96,12 @@ static struct sta_info *mesh_plink_alloc if (!sta) return NULL; - set_sta_flag(sta, WLAN_STA_AUTH); - set_sta_flag(sta, WLAN_STA_AUTHORIZED); + sta_info_move_state(sta, IEEE80211_STA_AUTH); + sta_info_move_state(sta, IEEE80211_STA_ASSOC); + sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED); + set_sta_flag(sta, WLAN_STA_WME); + sta->sta.supp_rates[local->hw.conf.channel->band] = rates; if (elems->ht_cap_elem) ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,net/mac80211/mlme.c 2011-12-13 21:03:10.000000000 +0100 renamed from net/mac80211/mlme.c 2011-12-13 21:01:26.000000000 +0100 +3
-3@@ -1577,10 +1577,10 @@ static bool ieee80211_assoc_success(stru return false; } - 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); if (!(ifmgd->flags & IEEE80211_STA_CONTROL_PORT)) - set_sta_flag(sta, WLAN_STA_AUTHORIZED); + sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED); rates = 0; basic_rates = 0;net/mac80211/tx.c 2011-12-13 21:03:10.000000000 +0100 renamed from net/mac80211/tx.c 2011-12-13 21:01:26.000000000 +0100 +0
-0@@ -295,7 +295,6 @@ ieee80211_tx_h_check_assoc(struct ieee80 if (likely(tx->flags & IEEE80211_TX_UNICAST)) {if (unlikely(!assoc &&
- tx->sdata->vif.type !=NL80211_IFTYPE_ADHOC&&ieee80211_is_data(hdr->frame_control))) { #ifdefCONFIG_MAC80211_VERBOSE_DEBUG
printk(KERN_DEBUG "%s: dropped data frame to not "--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Johannes Berg
maintainerRe: [RFC 2/4] mac80211: refactor station state transitions
Quoted 22 lines · Thomas Pedersen
Quoted 12 lines · Johannes Berg
From: Johannes Berg <[email protected]>
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.
Quoted 7 lines
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.
TBD:
WLAN_STA_TDLS_PEER_AUTH?
TBD: secure mesh AUTH transitions?
Quoted 6 lines
This patch makes it impossible to add a new unauthenticated station, AFAICT. Maybe this is not even desirable from mac80211's POV? The reason the secure mesh daemon adds a new unauthenticated peer is to stop
NL80211_NEW_PEER_CANDIDATEnotifications while userspace is handling the authentication process, and we need a station entry forieee80211_mgmt_tx().
Ah, yes. I had to sleep over this -- now I understand why I was confused. I'll amend the patch series to properly manage more of this in cfg80211. I have a feeling we should also allow userspace to manage the ASSOC state, but can we require it from the secure mesh userspace daemon? It would break backward compatibility if we do ... I'll try to find a workaround :)
johannes
Johannes Berg
maintainerRFC 3/4 mac80211: unwind station state on destroy
In reply to Johannes BergFrom: Johannes Berg <[email protected]>
Before destroying a station entry, unwind its
state so drivers and other code can rely on
state transitions happening.
--- net/mac80211/sta_info.c | 3 +++ net/mac80211/sta_info.h | 1 + 2 files changed, 4 insertions(+)
net/mac80211/sta_info.h +1 -0
@@ -74,6 +74,7 @@ enum ieee80211_sta_info_flags { };enum ieee80211_sta_state { +/* NOTE: These need to be ordered correctly! */ IEEE80211_STA_NONE ,IEEE80211_STA_AUTH ,IEEE80211_STA_ASSOC ,
net/mac80211/sta_info.c +3 -0
@@ -905,6 +905,9 @@ static int __must_check __sta_info_destrif (sdata->vif.type ==NL80211_IFTYPE_AP_VLAN )RCU_INIT_POINTER (sdata->u.vlan.sta,NULL ); +while (sta->sta_state >IEEE80211_STA_NONE ) +sta_info_move_state (sta, sta->sta_state -1 ); +if (sta->uploaded) {if (sdata->vif.type ==NL80211_IFTYPE_AP_VLAN ) sdata = container_of(sdata->bss,
Johannes Berg
maintainerRFC 4/4 mac80211: count authorized stations per BSS
In reply to Johannes BergFrom: Johannes Berg <[email protected]>
Currently, each AP interface will send multicast traffic if any interface has a station entry even if that station entry is allocated only. With the new station state management we can easily fix it by adding a counter that counts each authorized station only and send multicast traffic only when the correct interface has at least one authorized station.
--- net/mac80211/debugfs_netdev.c | 2 ++ net/mac80211/ieee80211_i.h | 1 + net/mac80211/sta_info.c | 14 +++++++++----- net/mac80211/tx.c | 19 ++++++++----------- 4 files changed, 20 insertions(+), 16 deletions(-)
net/mac80211/debugfs_netdev.c +2 -0
@@ -321,6 +321,7 @@ static ssize_t ieee80211_if_parse_tkip_m__IEEE80211_IF_FILE_W (tkip_mic_test);/* AP attributes */ +IEEE80211_IF_FILE (num_sta_authorized, u.ap.num_sta_authorized,ATOMIC );IEEE80211_IF_FILE (num_sta_ps, u.ap.num_sta_ps,ATOMIC );IEEE80211_IF_FILE (dtim_count, u.ap.dtim_count,DEC );
@@ -458,6 +459,7 @@ static void add_ap_files(struct ieee8021DEBUGFS_ADD (rc_rateidx_mask_2ghz);DEBUGFS_ADD (rc_rateidx_mask_5ghz); +DEBUGFS_ADD (num_sta_authorized);DEBUGFS_ADD (num_sta_ps);DEBUGFS_ADD (dtim_count);DEBUGFS_ADD (num_buffered_multicast);
net/mac80211/ieee80211_i.h +1 -0
@@ -243,6 +243,7 @@ struct ieee80211_if_ap {u8 tim[sizeof (unsigned long ) *BITS_TO_LONGS (IEEE80211_MAX_AID +1 )];struct sk_buff_head ps_bc_buf;atomic_t num_sta_ps;/* number of stations in PS mode */ +atomic_t num_sta_authorized;/* number of authorized stations */ int dtim_count;bool dtim_bc_mc; };
net/mac80211/sta_info.c +9 -5
@@ -1542,17 +1542,21 @@ int sta_info_move_state_checked(struct sreturn -EINVAL ;break ;case IEEE80211_STA_ASSOC : -if (sta->sta_state ==IEEE80211_STA_AUTH ) +if (sta->sta_state ==IEEE80211_STA_AUTH ) {set_bit (WLAN_STA_ASSOC , &sta->_flags); -else if (sta->sta_state ==IEEE80211_STA_AUTHORIZED ) + }else if (sta->sta_state ==IEEE80211_STA_AUTHORIZED ) { +if (sta->sdata->vif.type ==NL80211_IFTYPE_AP ) +atomic_dec (&sta->sdata->u.ap.num_sta_authorized);clear_bit (WLAN_STA_AUTHORIZED , &sta->_flags); -else + }else return -EINVAL ;break ;case IEEE80211_STA_AUTHORIZED : -if (sta->sta_state ==IEEE80211_STA_ASSOC ) +if (sta->sta_state ==IEEE80211_STA_ASSOC ) { +if (sta->sdata->vif.type ==NL80211_IFTYPE_AP ) +atomic_inc (&sta->sdata->u.ap.num_sta_authorized);set_bit (WLAN_STA_AUTHORIZED , &sta->_flags); -else + }else return -EINVAL ;break ;default :
net/mac80211/tx.c +8 -11
@@ -304,17 +304,14 @@ ieee80211_tx_h_check_assoc(struct ieee80I802_DEBUG_INC (tx->local->tx_handlers_drop_not_assoc);return TX_DROP ; } - }else { -if (unlikely (ieee80211_is_data (hdr->frame_control) && - tx->local->num_sta ==0 && - tx->sdata->vif.type !=NL80211_IFTYPE_ADHOC )) { -/* -* No associated STAs - no need to send multicast -* frames. -*/ -return TX_DROP ; - } -return TX_CONTINUE ; + }else if (unlikely (tx->sdata->vif.type ==NL80211_IFTYPE_AP && +ieee80211_is_data (hdr->frame_control) && + !atomic_read (&tx->sdata->u.ap.num_sta_authorized))) { +/* +* No associated STAs - no need to send multicast +* frames. +*/ +return TX_DROP ; }return TX_CONTINUE ;