From: Stanislaw Gruszka Date: Thu, 11 Jun 2015 10:53:45 +0000 (+0200) Subject: rt2800: fix assigning same WCID for different stations X-Git-Tag: v4.2-rc1~130^2~34^2~4 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=ed8e0ed53b317f72df907298fb653a976b083dc4;p=platform%2Fkernel%2Flinux-exynos.git rt2800: fix assigning same WCID for different stations On some hardware reading WCID entries table results getting 0xff numbers, no matter of value written there before. This cause assigning the same WCID for different stations and makes not possible to connect to more than one station. Signed-off-by: Stanislaw Gruszka Signed-off-by: Kalle Valo --- diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h index ebd5625..95c1d7c 100644 --- a/drivers/net/wireless/rt2x00/rt2800.h +++ b/drivers/net/wireless/rt2x00/rt2800.h @@ -2961,6 +2961,15 @@ enum rt2800_eeprom_word { #define BCN_TBTT_OFFSET 64 /* + * Hardware has 255 WCID table entries. First 32 entries are reserved for + * shared keys. Since parts of the pairwise key table might be shared with + * the beacon frame buffers 6 & 7 we could only use the first 222 entries. + */ +#define WCID_START 33 +#define WCID_END 222 +#define STA_IDS_SIZE (WCID_END - WCID_START + 2) + +/* * RT2800 driver data structure */ struct rt2800_drv_data { @@ -2971,6 +2980,7 @@ struct rt2800_drv_data { u8 txmixer_gain_24g; u8 txmixer_gain_5g; unsigned int tbtt_tick; + DECLARE_BITMAP(sta_ids, STA_IDS_SIZE); }; #endif /* RT2800_H */ diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index dfeca83..c784376 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -1381,38 +1381,6 @@ int rt2800_config_shared_key(struct rt2x00_dev *rt2x00dev, } EXPORT_SYMBOL_GPL(rt2800_config_shared_key); -static inline int rt2800_find_wcid(struct rt2x00_dev *rt2x00dev) -{ - struct mac_wcid_entry wcid_entry; - int idx; - u32 offset; - - /* - * Search for the first free WCID entry and return the corresponding - * index. - * - * Make sure the WCID starts _after_ the last possible shared key - * entry (>32). - * - * Since parts of the pairwise key table might be shared with - * the beacon frame buffers 6 & 7 we should only write into the - * first 222 entries. - */ - for (idx = 33; idx <= 222; idx++) { - offset = MAC_WCID_ENTRY(idx); - rt2800_register_multiread(rt2x00dev, offset, &wcid_entry, - sizeof(wcid_entry)); - if (is_broadcast_ether_addr(wcid_entry.mac)) - return idx; - } - - /* - * Use -1 to indicate that we don't have any more space in the WCID - * table. - */ - return -1; -} - int rt2800_config_pairwise_key(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_crypto *crypto, struct ieee80211_key_conf *key) @@ -1425,7 +1393,7 @@ int rt2800_config_pairwise_key(struct rt2x00_dev *rt2x00dev, * Allow key configuration only for STAs that are * known by the hw. */ - if (crypto->wcid < 0) + if (crypto->wcid > WCID_END) return -ENOSPC; key->hw_key_idx = crypto->wcid; @@ -1455,11 +1423,13 @@ int rt2800_sta_add(struct rt2x00_dev *rt2x00dev, struct ieee80211_vif *vif, { int wcid; struct rt2x00_sta *sta_priv = sta_to_rt2x00_sta(sta); + struct rt2800_drv_data *drv_data = rt2x00dev->drv_data; /* - * Find next free WCID. + * Search for the first free WCID entry and return the corresponding + * index. */ - wcid = rt2800_find_wcid(rt2x00dev); + wcid = find_first_zero_bit(drv_data->sta_ids, STA_IDS_SIZE) + WCID_START; /* * Store selected wcid even if it is invalid so that we can @@ -1471,9 +1441,11 @@ int rt2800_sta_add(struct rt2x00_dev *rt2x00dev, struct ieee80211_vif *vif, * No space left in the device, however, we can still communicate * with the STA -> No error. */ - if (wcid < 0) + if (wcid > WCID_END) return 0; + __set_bit(wcid - WCID_START, drv_data->sta_ids); + /* * Clean up WCID attributes and write STA address to the device. */ @@ -1487,11 +1459,16 @@ EXPORT_SYMBOL_GPL(rt2800_sta_add); int rt2800_sta_remove(struct rt2x00_dev *rt2x00dev, int wcid) { + struct rt2800_drv_data *drv_data = rt2x00dev->drv_data; + + if (wcid > WCID_END) + return 0; /* * Remove WCID entry, no need to clean the attributes as they will * get renewed when the WCID is reused. */ rt2800_config_wcid(rt2x00dev, NULL, wcid); + __clear_bit(wcid - WCID_START, drv_data->sta_ids); return 0; } @@ -7970,11 +7947,11 @@ int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, /* * Don't allow aggregation for stations the hardware isn't aware * of because tx status reports for frames to an unknown station - * always contain wcid=255 and thus we can't distinguish between - * multiple stations which leads to unwanted situations when the - * hw reorders frames due to aggregation. + * always contain wcid=WCID_END+1 and thus we can't distinguish + * between multiple stations which leads to unwanted situations + * when the hw reorders frames due to aggregation. */ - if (sta_priv->wcid < 0) + if (sta_priv->wcid > WCID_END) return 1; switch (action) { diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 1b8a459..3c26ee6 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -535,16 +535,8 @@ int rt2x00mac_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { struct rt2x00_dev *rt2x00dev = hw->priv; - struct rt2x00_sta *sta_priv = sta_to_rt2x00_sta(sta); - /* - * If there's no space left in the device table store - * -1 as wcid but tell mac80211 everything went ok. - */ - if (rt2x00dev->ops->lib->sta_add(rt2x00dev, vif, sta)) - sta_priv->wcid = -1; - - return 0; + return rt2x00dev->ops->lib->sta_add(rt2x00dev, vif, sta); } EXPORT_SYMBOL_GPL(rt2x00mac_sta_add); @@ -554,12 +546,6 @@ int rt2x00mac_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct rt2x00_dev *rt2x00dev = hw->priv; struct rt2x00_sta *sta_priv = sta_to_rt2x00_sta(sta); - /* - * If we never sent the STA to the device no need to clean it up. - */ - if (sta_priv->wcid < 0) - return 0; - return rt2x00dev->ops->lib->sta_remove(rt2x00dev, sta_priv->wcid); } EXPORT_SYMBOL_GPL(rt2x00mac_sta_remove);