diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2008-02-25 16:27:46 +0100 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-03-06 15:30:46 -0500 |
commit | d0709a65181beb787ef3f58cfe45536a2bb254c8 (patch) | |
tree | 29e5f36583b0e0a3f11b291347e57672eab41dad /net/mac80211/sta_info.h | |
parent | 5cf121c3cdb955583bf0c5d28c992b7968a4aa1a (diff) |
mac80211: RCU-ify STA info structure access
This makes access to the STA hash table/list use RCU to protect
against freeing of items. However, it's not a true RCU, the
copy step is missing: whenever somebody changes a STA item it
is simply updated. This is an existing race condition that is
now somewhat understandable.
This patch also fixes the race key freeing vs. STA destruction
by making sure that sta_info_destroy() is always called under
RTNL and frees the key.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/sta_info.h')
-rw-r--r-- | net/mac80211/sta_info.h | 61 |
1 files changed, 42 insertions, 19 deletions
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index b9dfb6fa893a..787124c253af 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -12,7 +12,6 @@ #include <linux/list.h> #include <linux/types.h> #include <linux/if_ether.h> -#include <linux/kref.h> #include "ieee80211_key.h" /** @@ -134,8 +133,14 @@ struct sta_ampdu_mlme { u8 dialog_token_allocator; }; + +/* see __sta_info_unlink */ +#define STA_INFO_PIN_STAT_NORMAL 0 +#define STA_INFO_PIN_STAT_PINNED 1 +#define STA_INFO_PIN_STAT_DESTROY 2 + + struct sta_info { - struct kref kref; struct list_head list; struct sta_info *hnext; /* next entry in hash table list */ @@ -166,8 +171,8 @@ struct sta_info { /* last rates used to send a frame to this STA */ int last_txrate_idx, last_nonerp_txrate_idx; - struct net_device *dev; /* which net device is this station associated - * to */ + /* sub_if_data this sta belongs to */ + struct ieee80211_sub_if_data *sdata; struct ieee80211_key *key; @@ -199,6 +204,12 @@ struct sta_info { u16 listen_interval; + /* + * for use by the internal lifetime management, + * see __sta_info_unlink + */ + u8 pin_status; + struct ieee80211_ht_info ht_info; /* 802.11n HT capabilities of this STA */ struct sta_ampdu_mlme ampdu_mlme; @@ -262,25 +273,37 @@ static inline enum plink_state sta_plink_state(struct sta_info *sta) */ #define STA_INFO_CLEANUP_INTERVAL (10 * HZ) -static inline void __sta_info_get(struct sta_info *sta) -{ - kref_get(&sta->kref); -} - -struct sta_info * sta_info_get(struct ieee80211_local *local, u8 *addr); +/* + * Get a STA info, must have be under RCU read lock. + */ +struct sta_info *sta_info_get(struct ieee80211_local *local, u8 *addr); +/* + * Get STA info by index, BROKEN! + */ struct sta_info *sta_info_get_by_idx(struct ieee80211_local *local, int idx, struct net_device *dev); -void sta_info_put(struct sta_info *sta); -struct sta_info *sta_info_add(struct ieee80211_local *local, - struct net_device *dev, u8 *addr, gfp_t gfp); -void sta_info_remove(struct sta_info *sta); -void sta_info_free(struct sta_info *sta); -void sta_info_init(struct ieee80211_local *local); -int sta_info_start(struct ieee80211_local *local); -void sta_info_stop(struct ieee80211_local *local); -void sta_info_flush(struct ieee80211_local *local, struct net_device *dev); +/* + * Add a new STA info, must be under RCU read lock + * because otherwise the returned reference isn't + * necessarily valid long enough. + */ +struct sta_info *sta_info_add(struct ieee80211_sub_if_data *sdata, + u8 *addr); +/* + * Unlink a STA info from the hash table/list. + * This can NULL the STA pointer if somebody else + * has already unlinked it. + */ +void sta_info_unlink(struct sta_info **sta); +void sta_info_destroy(struct sta_info *sta); void sta_info_set_tim_bit(struct sta_info *sta); void sta_info_clear_tim_bit(struct sta_info *sta); +void sta_info_init(struct ieee80211_local *local); +int sta_info_start(struct ieee80211_local *local); +void sta_info_stop(struct ieee80211_local *local); +void sta_info_flush(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata); + #endif /* STA_INFO_H */ |