more station handling refactoring
Johannes Berg
maintainercover more station handling refactoring
Here's another set of patches to refactor station handling, particularly station state handling (and fix a bug or two in the process).
The major work here is getting rid of dummy stations again and notifying drivers about state transitions (but state transition and sta_add/sta_remove callbacks will be mutually exclusive).
johannes
Johannes Berg
maintainerPATCH 1/8 mac80211: move managed mode station state modification
From: Johannes Berg <[email protected]>
Move the station state modification right before insert, this just makes the current code more readable (you can tell that it's before insertion looking at a single screenful of code) right now, but some upcoming changes will require this.
--- net/mac80211/mlme.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-)
net/mac80211/mlme.c +14 -14
@@ -1585,20 +1585,6 @@ static bool ieee80211_assoc_success(strureturn false; } - err =sta_info_move_state (sta,IEEE80211_STA_AUTH ); -if (!err) - err =sta_info_move_state (sta,IEEE80211_STA_ASSOC ); -if (!err && !(ifmgd->flags &IEEE80211_STA_CONTROL_PORT )) - err =sta_info_move_state (sta,IEEE80211_STA_AUTHORIZED ); -if (err) { -printk (KERN_DEBUG -"%s: failed to move station %pM to desired state\n" , - sdata->name, sta->sta.addr); -WARN_ON (__sta_info_destroy (sta)); -mutex_unlock (&sdata->local->sta_mtx); -return false; - } - rates =0 ; basic_rates =0 ; sband = local->hw.wiphy->bands[wk->chan->band];
@@ -1646,6 +1632,20 @@ static bool ieee80211_assoc_success(struif (elems.wmm_param)set_sta_flag (sta,WLAN_STA_WME ); + err =sta_info_move_state (sta,IEEE80211_STA_AUTH ); +if (!err) + err =sta_info_move_state (sta,IEEE80211_STA_ASSOC ); +if (!err && !(ifmgd->flags &IEEE80211_STA_CONTROL_PORT )) + err =sta_info_move_state (sta,IEEE80211_STA_AUTHORIZED ); +if (err) { +printk (KERN_DEBUG +"%s: failed to move station %pM to desired state\n" , + sdata->name, sta->sta.addr); +WARN_ON (__sta_info_destroy (sta)); +mutex_unlock (&sdata->local->sta_mtx); +return false; + } +/* sta_info_reinsert will also unlock the mutex lock */ err =sta_info_reinsert (sta); sta =NULL ;
Johannes Berg
maintainerPATCH 2/8 mac80211: simplify AP_VLAN handling
In reply to Johannes BergFrom: Johannes Berg <[email protected]>
Setting keys and updating TKIP keys must use the BSS sdata (not AP_VLAN), so we translate. Move the translation into driver-ops wrappers instead of having it inline in the code to simplify the normal code flow.
The same can be done for sta_add/remove which already does the translation in the wrapper.
--- net/mac80211/driver-ops.h | 2 ++ net/mac80211/key.c | 8 -------- net/mac80211/pm.c | 11 ++--------- net/mac80211/sta_info.c | 8 +------- net/mac80211/util.c | 11 ++--------- 5 files changed, 7 insertions(+), 33 deletions(-)
net/mac80211/driver-ops.h +2 -0
@@ -253,6 +253,7 @@ static inline int drv_set_key(struct ieemight_sleep (); + sdata =get_bss_sdata (sdata);check_sdata_in_driver (sdata);trace_drv_set_key (local, cmd, sdata, sta, key);
@@ -272,6 +273,7 @@ static inline void drv_update_tkip_key(sif (sta) ista = &sta->sta; + sdata =get_bss_sdata (sdata);check_sdata_in_driver (sdata);trace_drv_update_tkip_key (local, sdata, conf, ista, iv32);
net/mac80211/key.c +0 -8
@@ -123,9 +123,6 @@ static int ieee80211_key_enable_hw_accel*/ if (!(key->conf.flags &IEEE80211_KEY_FLAG_PAIRWISE )) goto out_unsupported; - sdata =container_of (sdata->bss, - struct ieee80211_sub_if_data, - u.ap); } ret =drv_set_key (key->local,SET_KEY , sdata, sta, &key->conf);
@@ -187,11 +184,6 @@ static void ieee80211_key_disable_hw_acc (key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)))increment_tailroom_need_count (sdata); -if (sdata->vif.type ==NL80211_IFTYPE_AP_VLAN ) - sdata =container_of (sdata->bss, - struct ieee80211_sub_if_data, - u.ap); - ret =drv_set_key (key->local,DISABLE_KEY , sdata, sta, &key->conf);
net/mac80211/pm.c +2 -9
@@ -97,15 +97,8 @@ int __ieee80211_suspend(struct ieee80211/* tear down aggregation sessions and remove STAs */ mutex_lock (&local->sta_mtx);list_for_each_entry (sta, &local->sta_list, list) { -if (sta->uploaded) { - sdata = sta->sdata; -if (sdata->vif.type ==NL80211_IFTYPE_AP_VLAN ) - sdata =container_of (sdata->bss, - struct ieee80211_sub_if_data, - u.ap); - -drv_sta_remove (local, sdata, &sta->sta); - } +if (sta->uploaded) +drv_sta_remove (local, sta->sdata, &sta->sta);mesh_plink_quiesce (sta); }
net/mac80211/sta_info.c +1 -7
@@ -774,14 +774,8 @@ int __must_check __sta_info_destroy(struWARN_ON_ONCE (err !=0 ); } -if (sta->uploaded) { -if (sdata->vif.type ==NL80211_IFTYPE_AP_VLAN ) - sdata =container_of (sdata->bss, - struct ieee80211_sub_if_data, - u.ap); +if (sta->uploaded)drv_sta_remove (local, sdata, &sta->sta); - sdata = sta->sdata; - }/* * At this point, after we wait for an RCU grace period,
net/mac80211/util.c +2 -9
@@ -1185,15 +1185,8 @@ int ieee80211_reconfig(struct ieee80211_/* add STAs back */ mutex_lock (&local->sta_mtx);list_for_each_entry (sta, &local->sta_list, list) { -if (sta->uploaded) { - sdata = sta->sdata; -if (sdata->vif.type ==NL80211_IFTYPE_AP_VLAN ) - sdata =container_of (sdata->bss, - struct ieee80211_sub_if_data, - u.ap); - -WARN_ON (drv_sta_add (local, sdata, &sta->sta)); - } +if (sta->uploaded) +WARN_ON (drv_sta_add (local, sta->sdata, &sta->sta)); }mutex_unlock (&local->sta_mtx);
Johannes Berg
maintainerPATCH 3/8 mac80211: dont program keys for stations not uploaded
In reply to Johannes BergFrom: Johannes Berg <[email protected]>
If a station couldn't be uploaded to the driver but is still kept (only in IBSS mode) we still shouldn't try to program the keys for it into hardware; fix this bug by skipping the key upload in this case.
--- net/mac80211/key.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-)
net/mac80211/key.c +14 -16
@@ -54,14 +54,6 @@ static void assert_key_lock(struct ieee8lockdep_assert_held (&local->key_mtx); } -static struct ieee80211_sta *get_sta_for_key (struct ieee80211_key *key) -{ -if (key->sta) -return &key->sta->sta; - -return NULL ; -} -static void increment_tailroom_need_count (struct ieee80211_sub_if_data *sdata) {/*
@@ -95,7 +87,7 @@ static void increment_tailroom_need_counstatic int ieee80211_key_enable_hw_accel (struct ieee80211_key *key) {struct ieee80211_sub_if_data *sdata; -struct ieee80211_sta *sta; +struct sta_info *sta;int ret;might_sleep ();
@@ -105,7 +97,7 @@ static int ieee80211_key_enable_hw_accelassert_key_lock (key->local); - sta =get_sta_for_key (key); + sta = key->sta;/* * If this is a per-STA GTK, check if it
@@ -115,6 +107,9 @@ static int ieee80211_key_enable_hw_accel !(key->local->hw.flags & IEEE80211_HW_SUPPORTS_PER_STA_GTK)) goto out_unsupported; +if (sta && !sta->uploaded) + goto out_unsupported; + sdata = key->sdata;if (sdata->vif.type ==NL80211_IFTYPE_AP_VLAN ) {/*
@@ -125,7 +120,8 @@ static int ieee80211_key_enable_hw_accel goto out_unsupported; } - ret =drv_set_key (key->local,SET_KEY , sdata, sta, &key->conf); + ret =drv_set_key (key->local,SET_KEY , sdata, + sta ? &sta->sta :NULL , &key->conf);if (!ret) { key->flags |=KEY_FLAG_UPLOADED_TO_HARDWARE ;
@@ -144,7 +140,8 @@ static int ieee80211_key_enable_hw_accelif (ret != -ENOSPC && ret != -EOPNOTSUPP )wiphy_err (key->local->hw.wiphy,"failed to set key (%d, %pM) to hardware (%d)\n" , - key->conf.keyidx, sta ? sta->addr : bcast_addr, ret); + key->conf.keyidx, + sta ? sta->sta.addr : bcast_addr, ret); out_unsupported:switch (key->conf.cipher) {
@@ -163,7 +160,7 @@ static int ieee80211_key_enable_hw_accelstatic void ieee80211_key_disable_hw_accel (struct ieee80211_key *key) {struct ieee80211_sub_if_data *sdata; -struct ieee80211_sta *sta; +struct sta_info *sta;int ret;might_sleep ();
@@ -176,7 +173,7 @@ static void ieee80211_key_disable_hw_accif (!(key->flags &KEY_FLAG_UPLOADED_TO_HARDWARE ))return ; - sta =get_sta_for_key (key); + sta = key->sta; sdata = key->sdata; if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) ||
@@ -185,12 +182,13 @@ static void ieee80211_key_disable_hw_accincrement_tailroom_need_count (sdata); ret =drv_set_key (key->local,DISABLE_KEY , sdata, - sta, &key->conf); + sta ? &sta->sta :NULL , &key->conf);if (ret)wiphy_err (key->local->hw.wiphy,"failed to remove key (%d, %pM) from hardware (%d)\n" , - key->conf.keyidx, sta ? sta->addr : bcast_addr, ret); + key->conf.keyidx, + sta ? sta->sta.addr : bcast_addr, ret); key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE ; }
Johannes Berg
maintainerPATCH 4/8 mac80211: add NOTEXIST station state
In reply to Johannes BergFrom: Johannes Berg <[email protected]>
This will be used by drivers later if they need to have stations inserted all the time, in mac80211 has no purpose, is never used and sta_state starts out in NONE.
--- net/mac80211/sta_info.c | 2 ++ net/mac80211/sta_info.h | 1 + 2 files changed, 3 insertions(+)
net/mac80211/sta_info.h +1 -0
@@ -77,6 +77,7 @@ enum ieee80211_sta_info_flags {enum ieee80211_sta_state {/* NOTE: These need to be ordered correctly! */ +IEEE80211_STA_NOTEXIST ,IEEE80211_STA_NONE ,IEEE80211_STA_AUTH ,IEEE80211_STA_ASSOC ,
net/mac80211/sta_info.c +2 -0
@@ -295,6 +295,8 @@ struct sta_info *sta_info_alloc(struct i sta->sdata = sdata; sta->last_rx = jiffies; + sta->sta_state =IEEE80211_STA_NONE ; +do_posix_clock_monotonic_gettime (&uptime); sta->last_connected = uptime.tv_sec;ewma_init (&sta->avg_signal,1024 ,8 );
Johannes Berg
maintainerPATCH 5/8 mac80211: add sta_state callback
In reply to Johannes BergFrom: Johannes Berg <[email protected]>
(based on Eliad's patch)
Add a callback to notify the low-level driver whenever the state of a station changes. The driver is only notified when the station is actually in the mac80211 hash table, not for pre-insert state transitions.
To allow the driver to replace sta_add/remove calls with this, call extra transitions with the NOTEXIST state.
This callback can fail, so we need to be careful in handling it when a station is inserted, particularly in the IBSS case where we still keep the station entry around for mac80211 purposes.
---
v2: call drv_sta_state() within the sta addition process (thanks Johannes) Johannes:
v3: - call drv_sta_state() in suspend
- introduce NOTEXIST state
- don't put old state into driver visible data but pass it to the callback -- also fixes a reconfig bug
- make exclusive (forbid having sta_add/remove and sta_state)
- allow drv_sta_state() to fail and unwind initial addition if it does
include/net/mac80211.h | 30 +++++++++++++++++++++ net/mac80211/driver-ops.h | 22 +++++++++++++++ net/mac80211/driver-trace.h | 32 +++++++++++++++++++++++ net/mac80211/main.c | 3 ++ net/mac80211/pm.c | 10 ++++++- net/mac80211/sta_info.c | 61 ++++++++++++++++++++++++++++++++++++++++---- net/mac80211/sta_info.h | 9 ------ net/mac80211/util.c | 10 ++++++- 8 files changed, 161 insertions(+), 16 deletions(-)
include/net/mac80211.h +30 -0
@@ -962,6 +962,25 @@ enum set_key_cmd { };/** +* enum ieee80211_sta_state - station state +* +* @IEEE80211_STA_NOTEXIST: station doesn't exist at all, +* this is a special state for add/remove transitions +* @IEEE80211_STA_NONE: station exists without special state +* @IEEE80211_STA_AUTH: station is authenticated +* @IEEE80211_STA_ASSOC: station is associated +* @IEEE80211_STA_AUTHORIZED: station is authorized (802.1X) +*/ +enum ieee80211_sta_state { +/* NOTE: These need to be ordered correctly! */ +IEEE80211_STA_NOTEXIST , +IEEE80211_STA_NONE , +IEEE80211_STA_AUTH , +IEEE80211_STA_ASSOC , +IEEE80211_STA_AUTHORIZED , +}; + +/** * struct ieee80211_sta - station table entry * * A station table entry represents a station we are possibly
@@ -1963,6 +1982,13 @@ enum ieee80211_frame_release_type {* in AP mode, this callback will not be called when the flag * %IEEE80211_HW_AP_LINK_PS is set. Must be atomic. * +* @sta_state: Notifies low level driver about state transition of a +* station (which can be the AP, a client, IBSS/WDS/mesh peer etc.) +* This callback is mutually exclusive with @sta_add/@sta_remove. +* It must not fail for down transitions but may fail for transitions +* up the list of states. +* The callback can sleep. +* * @conf_tx: Configure TX queue parameters (EDCF (aifs, cw_min, cw_max), * bursting) for a hardware TX queue. * Returns a negative error code on failure.
@@ -2182,6 +2208,10 @@ struct ieee80211_ops { struct ieee80211_sta *sta);void (*sta_notify)(struct ieee80211_hw *hw,struct ieee80211_vif *vif,enum sta_notify_cmd ,struct ieee80211_sta *sta); +int (*sta_state)(struct ieee80211_hw *hw,struct ieee80211_vif *vif, +struct ieee80211_sta *sta, +enum ieee80211_sta_state old_state, +enum ieee80211_sta_state new_state);int (*conf_tx)(struct ieee80211_hw *hw,struct ieee80211_vif *vif,u16 queue,const struct ieee80211_tx_queue_params *params);
net/mac80211/driver-ops.h +22 -0
@@ -478,6 +478,28 @@ static inline void drv_sta_remove(structtrace_drv_return_void (local); } +static inline __must_check +int drv_sta_state (struct ieee80211_local *local, +struct ieee80211_sub_if_data *sdata, +struct sta_info *sta, +enum ieee80211_sta_state old_state, +enum ieee80211_sta_state new_state) +{ +int ret =0 ; + +might_sleep (); + + sdata =get_bss_sdata (sdata); +check_sdata_in_driver (sdata); + +trace_drv_sta_state (local, sdata, &sta->sta, old_state, new_state); +if (local->ops->sta_state) + ret = local->ops->sta_state (&local->hw, &sdata->vif, &sta->sta, + old_state, new_state); +trace_drv_return_int (local, ret); +return ret; +} +static inline int drv_conf_tx (struct ieee80211_local *local,struct ieee80211_sub_if_data *sdata,u16 queue,const struct ieee80211_tx_queue_params *params)
net/mac80211/driver-trace.h +32 -0
@@ -635,6 +635,38 @@ TRACE_EVENT(drv_sta_notify, ) ); +TRACE_EVENT (drv_sta_state, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + struct ieee80211_sta *sta, + enum ieee80211_sta_state old_state, + enum ieee80211_sta_state new_state), + +TP_ARGS (local, sdata, sta, old_state, new_state), + +TP_STRUCT__entry ( + LOCAL_ENTRY + VIF_ENTRY + STA_ENTRY + __field(u32, old_state) +__field (u32, new_state) + ), + +TP_fast_assign ( + LOCAL_ASSIGN; + VIF_ASSIGN; + STA_ASSIGN; + __entry->old_state = old_state; + __entry->new_state = new_state; + ), + +TP_printk ( + LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " state: %d->%d", +LOCAL_PR_ARG ,VIF_PR_ARG ,STA_PR_ARG , + __entry->old_state, __entry->new_state + ) +); + TRACE_EVENT(drv_sta_add, TP_PROTO(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata,
net/mac80211/sta_info.c +56 -5
88 lines not on this page · raw message
net/mac80211/util.c +9 -1
@@ -1185,8 +1185,16 @@ int ieee80211_reconfig(struct ieee80211_/* add STAs back */ mutex_lock (&local->sta_mtx);list_for_each_entry (sta, &local->sta_list, list) { -if (sta->uploaded) +if (sta->uploaded) { +enum ieee80211_sta_state state; +WARN_ON (drv_sta_add (local, sta->sdata, &sta->sta)); + +for (state =IEEE80211_STA_NOTEXIST ; + state < sta->sta_state -1 ; state++) +WARN_ON (drv_sta_state (local, sta->sdata, sta, + state, state +1 )); + } }mutex_unlock (&local->sta_mtx);
net/mac80211/main.c +3 -0
@@ -534,6 +534,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(int priv_size, i;struct wiphy *wiphy; +if (WARN_ON (ops->sta_state && (ops->sta_add || ops->sta_remove))) +return NULL ; +/* Ensure 32-byte alignment of our private data and hw private data. * We use the wiphy priv data for both our ieee80211_local and for * the driver's private data
net/mac80211/sta_info.h +0 -9
@@ -75,15 +75,6 @@ enum ieee80211_sta_info_flags { WLAN_STA_INSERTED, }; -enum ieee80211_sta_state { -/* NOTE: These need to be ordered correctly! */ -IEEE80211_STA_NOTEXIST , -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 15
net/mac80211/pm.c +9 -1
@@ -97,9 +97,17 @@ int __ieee80211_suspend(struct ieee80211/* tear down aggregation sessions and remove STAs */ mutex_lock (&local->sta_mtx);list_for_each_entry (sta, &local->sta_list, list) { -if (sta->uploaded) +if (sta->uploaded) { +enum ieee80211_sta_state state; +drv_sta_remove (local, sta->sdata, &sta->sta); + state = sta->sta_state; +for (; state >IEEE80211_STA_NOTEXIST ; state--) +WARN_ON (drv_sta_state (local, sdata, sta, + state, state -1 )); + } +mesh_plink_quiesce (sta); }mutex_unlock (&local->sta_mtx);
Johannes Berg
maintainerPATCH 6/8 mac80211: implement sta_add/sta_remove in sta_state
In reply to Johannes BergFrom: Johannes Berg <[email protected]>
Instead of maintaining separate sta_add/sta_remove callsites, implement it in sta_state when the driver has no sta_state implementation.
The only behavioural change this should cause is in secure mesh mode: with this the station entries will only be created after the stations are set to AUTH. Given which drivers support mesh, this seems to not be a problem.
--- net/mac80211/driver-ops.h | 11 ++++++++++- net/mac80211/pm.c | 2 -- net/mac80211/sta_info.c | 23 +++++++++-------------- net/mac80211/util.c | 2 -- 4 files changed, 19 insertions(+), 19 deletions(-)
net/mac80211/sta_info.c +9 -14
@@ -367,7 +367,12 @@ static int sta_info_insert_drv_state(str }if (!err) { - sta->uploaded = true; +/* +* Drivers using legacy sta_add/sta_remove callbacks only +* get uploaded set to true after sta_add is called. +*/ +if (!local->ops->sta_add) + sta->uploaded = true;return 0 ; }
@@ -419,18 +424,9 @@ static int sta_info_insert_finish(structif (!sta->dummy || dummy_reinsert) {/* notify driver */ - err =drv_sta_add (local, sdata, &sta->sta); -if (err) { -if (sdata->vif.type !=NL80211_IFTYPE_ADHOC ) - goto out_err; -printk (KERN_DEBUG "%s: failed to add IBSS STA %pM to " -"driver (%d) - keeping it anyway.\n" , - sdata->name, sta->sta.addr, err); - }else { - err =sta_info_insert_drv_state (local, sdata, sta); -if (err) - goto out_err; - } + err =sta_info_insert_drv_state (local, sdata, sta); +if (err) + goto out_err; }if (!dummy_reinsert) {
@@ -812,7 +808,6 @@ int __must_check __sta_info_destroy(stru }if (sta->uploaded) { -drv_sta_remove (local, sdata, &sta->sta); ret =drv_sta_state (local, sdata, sta,IEEE80211_STA_NONE ,IEEE80211_STA_NOTEXIST );WARN_ON_ONCE (ret !=0 );
net/mac80211/util.c +0 -2
@@ -1188,8 +1188,6 @@ int ieee80211_reconfig(struct ieee80211_if (sta->uploaded) {enum ieee80211_sta_state state; -WARN_ON (drv_sta_add (local, sta->sdata, &sta->sta)); -for (state =IEEE80211_STA_NOTEXIST ; state < sta->sta_state -1 ; state++) WARN_ON(drv_sta_state(local, sta->sdata, sta,
net/mac80211/pm.c +0 -2
@@ -100,8 +100,6 @@ int __ieee80211_suspend(struct ieee80211if (sta->uploaded) {enum ieee80211_sta_state state; -drv_sta_remove (local, sta->sdata, &sta->sta); - state = sta->sta_state;for (; state >IEEE80211_STA_NOTEXIST ; state--) WARN_ON(drv_sta_state(local, sdata, sta,
net/mac80211/driver-ops.h +10 -1
@@ -493,9 +493,18 @@ int drv_sta_state(struct ieee80211_localcheck_sdata_in_driver (sdata);trace_drv_sta_state (local, sdata, &sta->sta, old_state, new_state); -if (local->ops->sta_state) +if (local->ops->sta_state) { ret = local->ops->sta_state (&local->hw, &sdata->vif, &sta->sta, old_state, new_state); + }else if (old_state ==IEEE80211_STA_AUTH && + new_state ==IEEE80211_STA_ASSOC ) { + ret =drv_sta_add (local, sdata, &sta->sta); +if (ret ==0 ) + sta->uploaded = true; + }else if (old_state ==IEEE80211_STA_ASSOC && + new_state ==IEEE80211_STA_AUTH ) { +drv_sta_remove (local, sdata, &sta->sta); + }trace_drv_return_int (local, ret);return ret; }
Johannes Berg
maintainerPATCH 7/8 mac80211: call rate control only after init
In reply to Johannes BergFrom: Johannes Berg <[email protected]>
There are situations where we don't have the necessary rate control information yet for station entries, e.g. when associating. This currently doesn't really happen due to the dummy station handling; explicitly disabling rate control when it's not initialised will allow us to remove dummy stations.
--- net/mac80211/debugfs_sta.c | 4 ++-- net/mac80211/rate.c | 2 +- net/mac80211/rate.h | 1 + net/mac80211/sta_info.h | 2 ++ 4 files changed, 6 insertions(+), 3 deletions(-)
net/mac80211/debugfs_sta.c +2 -2
@@ -63,7 +63,7 @@ static ssize_t sta_flags_read(struct fil test_sta_flag(sta, WLAN_STA_##flg) ? #flg "\n" : "" int res = scnprintf(buf, sizeof(buf), - "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", + "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", TEST(AUTH), TEST(ASSOC), TEST(PS_STA), TEST(PS_DRIVER), TEST(AUTHORIZED), TEST(SHORT_PREAMBLE),
@@ -71,7 +71,7 @@ static ssize_t sta_flags_read(struct filTEST (MFP ),TEST (BLOCK_BA ),TEST (PSPOLL ),TEST (UAPSD ),TEST (SP ),TEST (TDLS_PEER ), TEST(TDLS_PEER_AUTH), TEST(4ADDR_EVENT), - TEST(INSERTED)); + TEST(INSERTED), TEST(RATE_CONTROL));#undef TESTreturn simple_read_from_buffer (userbuf, count, ppos, buf, res); }
net/mac80211/rate.c +1 -1
@@ -336,7 +336,7 @@ void rate_control_get_rate(struct ieee80int i;u32 mask; -if (sta) { +if (sta &&test_sta_flag (sta,WLAN_STA_RATE_CONTROL )) { ista = &sta->sta; priv_sta = sta->rate_ctrl_priv; }
net/mac80211/rate.h +1 -0
@@ -62,6 +62,7 @@ static inline void rate_control_rate_ini sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; ref->ops->rate_init (ref->priv, sband, ista, priv_sta); +set_sta_flag (sta,WLAN_STA_RATE_CONTROL ); } static inline void rate_control_rate_update(struct ieee80211_local *local,
net/mac80211/sta_info.h +2 -0
@@ -53,6 +53,7 @@* reply to other uAPSD trigger frames or PS-Poll. * @WLAN_STA_4ADDR_EVENT: 4-addr event was already sent for this frame. * @WLAN_STA_INSERTED: This station is inserted into the hash table. +* @WLAN_STA_RATE_CONTROL: rate control was initialized for this station. */ enum ieee80211_sta_info_flags {WLAN_STA_AUTH ,
@@ -73,6 +74,7 @@ enum ieee80211_sta_info_flags {WLAN_STA_SP ,WLAN_STA_4ADDR_EVENT ,WLAN_STA_INSERTED , + WLAN_STA_RATE_CONTROL, };#define STA_TID_NUM 16
Johannes Berg
maintainerPATCH 8/8 mac80211: remove dummy STA support
In reply to Johannes BergFrom: Johannes Berg <[email protected]>
The dummy STA support was added because I didn't want to change the driver API at the time. Now that we have state transitions triggering station add/remove in the driver, we only call add once a station reaches ASSOCIATED, so we can remove the dummy station stuff again.
While at it, tighten the RX check and accept only port control (EAP) frames from the AP station if it's not associated yet -- in other cases there's no race.
--- net/mac80211/mlme.c | 15 +---- net/mac80211/rx.c | 13 +++- net/mac80211/sta_info.c | 135 ++++++++---------------------------------------- net/mac80211/sta_info.h | 30 ---------- 4 files changed, 38 insertions(+), 155 deletions(-)
net/mac80211/sta_info.h +1 -29
@@ -267,8 +267,6 @@ struct sta_ampdu_mlme {* @dead: set to true when sta is unlinked * @uploaded: set to true when sta is uploaded to the driver * @lost_packets: number of consecutive lost packets -* @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) * @beacon_loss_count: number of times beacon loss has triggered
@@ -366,9 +364,6 @@ struct sta_info {unsigned int lost_packets;unsigned int beacon_loss_count; -/* should be right in front of sta to be in the same cache line */ -bool dummy; -/* keep last! */ struct ieee80211_sta sta; };
@@ -470,15 +465,9 @@ rcu_dereference_protected_tid_tx(structstruct sta_info *sta_info_get (struct ieee80211_sub_if_data *sdata,const u8 *addr); -struct sta_info *sta_info_get_rx (struct ieee80211_sub_if_data *sdata, -const u8 *addr); -struct sta_info *sta_info_get_bss (struct ieee80211_sub_if_data *sdata,const u8 *addr); -struct sta_info *sta_info_get_bss_rx (struct ieee80211_sub_if_data *sdata, -const u8 *addr); - static inline void for_each_sta_info_type_check(struct ieee80211_local *local, const u8 *addr,
@@ -487,23 +476,7 @@ void for_each_sta_info_type_check(struct { } -#define for_each_sta_info (local, _addr, _sta, nxt) \ - for (/* initialise loop */ \ - _sta =rcu_dereference (local->sta_hash[STA_HASH (_addr)]),\ - nxt = _sta ?rcu_dereference (_sta->hnext) :NULL ; \ -/* typecheck */ \ -for_each_sta_info_type_check (local, (_addr), _sta, nxt),\ -/* continue condition */ \ - _sta; \ -/* advance loop */ \ - _sta = nxt, \ - nxt = _sta ? rcu_dereference(_sta->hnext) : NULL \ - ) \ -/* run code only if address matches and it's not a dummy sta */ \ -if (memcmp (_sta->sta.addr, (_addr),ETH_ALEN ) ==0 && \ - !_sta->dummy) - -#define for_each_sta_info_rx (local, _addr, _sta, nxt) \ +#define for_each_sta_info (local, _addr, _sta, nxt) \ for (/* initialise loop */ \ _sta =rcu_dereference (local->sta_hash[STA_HASH (_addr)]),\ nxt = _sta ?rcu_dereference (_sta->hnext) :NULL ; \
@@ -542,7 +515,6 @@ void sta_info_free(struct ieee80211_loca*/ int sta_info_insert (struct sta_info *sta); int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU); -int sta_info_reinsert (struct sta_info *sta);int __must_check __sta_info_destroy (struct sta_info *sta); int sta_info_destroy_addr(struct ieee80211_sub_if_data *sdata,
net/mac80211/sta_info.c +25 -110
185 lines not on this page · raw message
net/mac80211/mlme.c +3 -12
@@ -1579,7 +1579,7 @@ static bool ieee80211_assoc_success(stru* station info was already allocated and inserted before * the association and should be available to us */ - sta =sta_info_get_rx (sdata, cbss->bssid); + sta =sta_info_get (sdata, cbss->bssid);if (WARN_ON (!sta)) {mutex_unlock (&sdata->local->sta_mtx);return false;
@@ -1646,14 +1646,7 @@ static bool ieee80211_assoc_success(strureturn false; } -/* sta_info_reinsert will also unlock the mutex lock */ - err =sta_info_reinsert (sta); - sta =NULL ; -if (err) { -printk (KERN_DEBUG "%s: failed to insert STA entry for" -" the AP (error %d)\n" , sdata->name, err); -return false; - } +mutex_unlock (&sdata->local->sta_mtx);/* * Always handle WMM once after association regardless
@@ -2534,12 +2527,10 @@ static int ieee80211_pre_assoc(struct ieif (!sta)return -ENOMEM ; - sta->dummy = true; - err =sta_info_insert (sta); sta =NULL ;if (err) { -printk (KERN_DEBUG "%s: failed to insert Dummy STA entry for" +printk (KERN_DEBUG "%s: failed to insert STA entry for" " the AP (error %d)\n" , sdata->name, err);return err; }
net/mac80211/rx.c +9 -4
@@ -859,7 +859,12 @@ ieee80211_rx_h_check(struct ieee80211_rx rx->sdata->vif.type != NL80211_IFTYPE_ADHOC && rx->sdata->vif.type != NL80211_IFTYPE_WDS && (!rx->sta || !test_sta_flag(rx->sta, WLAN_STA_ASSOC)))) { - if (rx->sta && rx->sta->dummy && +/* +* accept port control frames from the AP even when it's not +* yet marked ASSOC to prevent a race where we don't set the +* assoc bit quickly enough before it sends the first frame +*/ +if (rx->sta && rx->sdata->vif.type ==NL80211_IFTYPE_STATION &&ieee80211_is_data_present (hdr->frame_control)) {u16 ethertype;u8 *payload;
@@ -2975,7 +2980,7 @@ static void __ieee80211_rx_handle_packetif (ieee80211_is_data (fc)) { prev_sta =NULL ; -for_each_sta_info_rx (local, hdr->addr2, sta, tmp) { +for_each_sta_info (local, hdr->addr2, sta, tmp) {if (!prev_sta) { prev_sta = sta;continue ;
@@ -3019,7 +3024,7 @@ static void __ieee80211_rx_handle_packetcontinue ; } - rx.sta =sta_info_get_bss_rx (prev, hdr->addr2); + rx.sta =sta_info_get_bss (prev, hdr->addr2); rx.sdata = prev;ieee80211_prepare_and_rx_handle (&rx, skb, false);
@@ -3027,7 +3032,7 @@ static void __ieee80211_rx_handle_packet }if (prev) { - rx.sta =sta_info_get_bss_rx (prev, hdr->addr2); + rx.sta =sta_info_get_bss (prev, hdr->addr2); rx.sdata = prev;if (ieee80211_prepare_and_rx_handle (&rx, skb, true))
Johannes Berg
maintainerQuoted 8 lines · Johannes Berg
Here's another set of patches to refactor station handling, particularly station state handling (and fix a bug or two in the process).
The major work here is getting rid of dummy stations again and notifying drivers about state transitions (but state transition and sta_add/sta_remove callbacks will be mutually exclusive).
Eliad identified a few issues here -- John, please drop this patchset, I'll resend.
johannes