From 3434fbd39862d471c92b66c28cd449deea8e9f90 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 3 May 2008 00:59:37 +0200 Subject: mac80211: require four hardware queues for QoS/HT This patch makes mac80211 only announce QoS/HT support when the underlying hardware has four (or more) queues. Signed-off-by: Johannes Berg Cc: Ron Rindjunksi Signed-off-by: John W. Linville --- net/mac80211/mlme.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) (limited to 'net/mac80211/mlme.c') diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 55b85ae5bc11..108c6fc42fe2 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -272,6 +272,12 @@ static void ieee80211_sta_wmm_params(struct net_device *dev, int count; u8 *pos; + if (!(ifsta->flags & IEEE80211_STA_WMM_ENABLED)) + return; + + if (!wmm_param) + return; + if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1) return; count = wmm_param[6] & 0x0f; @@ -763,8 +769,10 @@ static void ieee80211_send_assoc(struct net_device *dev, *pos++ = 1; /* WME ver */ *pos++ = 0; } + /* wmm support is a must to HT */ - if (wmm && sband->ht_info.ht_supported) { + if (wmm && (ifsta->flags & IEEE80211_STA_WMM_ENABLED) && + sband->ht_info.ht_supported) { __le16 tmp = cpu_to_le16(sband->ht_info.cap); pos = skb_put(skb, sizeof(struct ieee80211_ht_cap)+2); *pos++ = WLAN_EID_HT_CAPABILITY; @@ -2021,7 +2029,8 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, else sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; - if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param) { + if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param && + (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) { struct ieee80211_ht_bss_info bss_info; ieee80211_ht_cap_ie_to_ht_info( (struct ieee80211_ht_cap *) @@ -2034,7 +2043,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, rate_control_rate_init(sta, local); - if (elems.wmm_param && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) { + if (elems.wmm_param) { sta->flags |= WLAN_STA_WME; rcu_read_unlock(); ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param, @@ -2817,10 +2826,8 @@ static void ieee80211_rx_mgmt_beacon(struct net_device *dev, ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems); - if (elems.wmm_param && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) { - ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param, - elems.wmm_param_len); - } + ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param, + elems.wmm_param_len); /* Do not send changes to driver if we are scanning. This removes * requirement that driver's bss_info_changed function needs to be -- cgit v1.2.3 From 07346f81e87d6e4cca7ae9adfa711d0c61c87b56 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 3 May 2008 01:02:02 +0200 Subject: mac80211: proper STA info locking As discussed earlier, we can unify locking in struct sta_info and use just a single spinlock protecting all members of the structure that need protection. Many don't, but one of the especially bad ones is the 'flags' member that can currently be clobbered when RX and TX is being processed on different CPUs at the same time. Because having four spinlocks for different, mostly exclusive parts of a single structure is overkill, this patch also kills the ampdu and mesh plink spinlocks and uses just a single one for everything. Because none of the spinlocks are nested, this is safe. It remains to be seen whether or not we should make the sta flags use atomic bit operations instead, for now though this is a safe thing and using atomic operations instead will be very simple using the new static inline functions this patch introduces for accessing sta->flags. Since spin_lock_bh() is used with this lock, there shouldn't be any contention even if aggregation is enabled at around the same time as both requires frame transmission/reception which is in a bh context. Signed-off-by: Johannes Berg Cc: Tomas Winkler Cc: Ron Rindjunsky Cc: Luis Carlos Cobo Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965-rs.c | 4 +- net/mac80211/cfg.c | 2 + net/mac80211/debugfs_sta.c | 15 ++--- net/mac80211/key.c | 4 +- net/mac80211/main.c | 31 ++++++----- net/mac80211/mesh_plink.c | 88 +++++++++++++++--------------- net/mac80211/mlme.c | 38 ++++++------- net/mac80211/rx.c | 17 +++--- net/mac80211/sta_info.c | 14 ++--- net/mac80211/sta_info.h | 72 +++++++++++++++++++++--- net/mac80211/tx.c | 21 +++---- 11 files changed, 181 insertions(+), 125 deletions(-) (limited to 'net/mac80211/mlme.c') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index 67356d9a0c59..e3444c4ea1a5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -360,9 +360,9 @@ static void rs_tl_turn_on_agg_for_tid(struct iwl_priv *priv, unsigned long state; DECLARE_MAC_BUF(mac); - spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_lock_bh(&sta->lock); state = sta->ampdu_mlme.tid_state_tx[tid]; - spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_unlock_bh(&sta->lock); if (state == HT_AGG_STATE_IDLE && rs_tl_get_load(lq_data, tid) > IWL_AGG_LOAD_THRESHOLD) { diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 699d97b8de5e..3cef80dcd0e5 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -602,6 +602,7 @@ static void sta_apply_parameters(struct ieee80211_local *local, */ if (params->station_flags & STATION_FLAG_CHANGED) { + spin_lock_bh(&sta->lock); sta->flags &= ~WLAN_STA_AUTHORIZED; if (params->station_flags & STATION_FLAG_AUTHORIZED) sta->flags |= WLAN_STA_AUTHORIZED; @@ -613,6 +614,7 @@ static void sta_apply_parameters(struct ieee80211_local *local, sta->flags &= ~WLAN_STA_WME; if (params->station_flags & STATION_FLAG_WME) sta->flags |= WLAN_STA_WME; + spin_unlock_bh(&sta->lock); } /* diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 676a93202ff9..1f00273d99c2 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -74,14 +74,15 @@ static ssize_t sta_flags_read(struct file *file, char __user *userbuf, { char buf[100]; struct sta_info *sta = file->private_data; + u32 staflags = get_sta_flags(sta); int res = scnprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s", - sta->flags & WLAN_STA_AUTH ? "AUTH\n" : "", - sta->flags & WLAN_STA_ASSOC ? "ASSOC\n" : "", - sta->flags & WLAN_STA_PS ? "PS\n" : "", - sta->flags & WLAN_STA_AUTHORIZED ? "AUTHORIZED\n" : "", - sta->flags & WLAN_STA_SHORT_PREAMBLE ? "SHORT PREAMBLE\n" : "", - sta->flags & WLAN_STA_WME ? "WME\n" : "", - sta->flags & WLAN_STA_WDS ? "WDS\n" : ""); + staflags & WLAN_STA_AUTH ? "AUTH\n" : "", + staflags & WLAN_STA_ASSOC ? "ASSOC\n" : "", + staflags & WLAN_STA_PS ? "PS\n" : "", + staflags & WLAN_STA_AUTHORIZED ? "AUTHORIZED\n" : "", + staflags & WLAN_STA_SHORT_PREAMBLE ? "SHORT PREAMBLE\n" : "", + staflags & WLAN_STA_WME ? "WME\n" : "", + staflags & WLAN_STA_WDS ? "WDS\n" : ""); return simple_read_from_buffer(userbuf, count, ppos, buf, res); } STA_OPS(flags); diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 88b211af7c1f..d4893bd17754 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -321,7 +321,7 @@ void ieee80211_key_link(struct ieee80211_key *key, * some hardware cannot handle TKIP with QoS, so * we indicate whether QoS could be in use. */ - if (sta->flags & WLAN_STA_WME) + if (test_sta_flags(sta, WLAN_STA_WME)) key->conf.flags |= IEEE80211_KEY_FLAG_WMM_STA; /* @@ -342,7 +342,7 @@ void ieee80211_key_link(struct ieee80211_key *key, /* same here, the AP could be using QoS */ ap = sta_info_get(key->local, key->sdata->u.sta.bssid); if (ap) { - if (ap->flags & WLAN_STA_WME) + if (test_sta_flags(ap, WLAN_STA_WME)) key->conf.flags |= IEEE80211_KEY_FLAG_WMM_STA; } diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 55e76117da9e..f277407f0f5a 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -346,6 +346,7 @@ static int ieee80211_open(struct net_device *dev) goto err_del_interface; } + /* no locking required since STA is not live yet */ sta->flags |= WLAN_STA_AUTHORIZED; res = sta_info_insert(sta); @@ -588,7 +589,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) return -ENOENT; } - spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_lock_bh(&sta->lock); /* we have tried too many times, receiver does not want A-MPDU */ if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) { @@ -691,7 +692,7 @@ start_ba_err: spin_unlock_bh(&local->mdev->queue_lock); ret = -EBUSY; start_ba_exit: - spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_unlock_bh(&sta->lock); rcu_read_unlock(); return ret; } @@ -719,7 +720,7 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw, /* check if the TID is in aggregation */ state = &sta->ampdu_mlme.tid_state_tx[tid]; - spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_lock_bh(&sta->lock); if (*state != HT_AGG_STATE_OPERATIONAL) { ret = -ENOENT; @@ -749,7 +750,7 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw, } stop_BA_exit: - spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_unlock_bh(&sta->lock); rcu_read_unlock(); return ret; } @@ -778,12 +779,12 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid) } state = &sta->ampdu_mlme.tid_state_tx[tid]; - spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_lock_bh(&sta->lock); if (!(*state & HT_ADDBA_REQUESTED_MSK)) { printk(KERN_DEBUG "addBA was not requested yet, state is %d\n", *state); - spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_unlock_bh(&sta->lock); rcu_read_unlock(); return; } @@ -796,7 +797,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid) printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid); ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]); } - spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_unlock_bh(&sta->lock); rcu_read_unlock(); } EXPORT_SYMBOL(ieee80211_start_tx_ba_cb); @@ -830,10 +831,10 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid) } state = &sta->ampdu_mlme.tid_state_tx[tid]; - spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_lock_bh(&sta->lock); if ((*state & HT_AGG_STATE_REQ_STOP_BA_MSK) == 0) { printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n"); - spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_unlock_bh(&sta->lock); rcu_read_unlock(); return; } @@ -860,7 +861,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid) sta->ampdu_mlme.addba_req_num[tid] = 0; kfree(sta->ampdu_mlme.tid_tx[tid]); sta->ampdu_mlme.tid_tx[tid] = NULL; - spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_unlock_bh(&sta->lock); rcu_read_unlock(); } @@ -1315,7 +1316,7 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, * packet. If the STA went to power save mode, this will happen * happen when it wakes up for the next time. */ - sta->flags |= WLAN_STA_CLEAR_PS_FILT; + set_sta_flags(sta, WLAN_STA_CLEAR_PS_FILT); /* * This code races in the following way: @@ -1347,7 +1348,7 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, * can be unknown, for example with different interrupt status * bits. */ - if (sta->flags & WLAN_STA_PS && + if (test_sta_flags(sta, WLAN_STA_PS) && skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) { ieee80211_remove_tx_extra(local, sta->key, skb, &status->control); @@ -1355,7 +1356,7 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, return; } - if (!(sta->flags & WLAN_STA_PS) && + if (!test_sta_flags(sta, WLAN_STA_PS) && !(status->control.flags & IEEE80211_TXCTL_REQUEUE)) { /* Software retry the packet once */ status->control.flags |= IEEE80211_TXCTL_REQUEUE; @@ -1370,7 +1371,7 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, "queue_len=%d PS=%d @%lu\n", wiphy_name(local->hw.wiphy), skb_queue_len(&sta->tx_filtered), - !!(sta->flags & WLAN_STA_PS), jiffies); + !!test_sta_flags(sta, WLAN_STA_PS), jiffies); dev_kfree_skb(skb); } @@ -1399,7 +1400,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, struct sta_info *sta; sta = sta_info_get(local, hdr->addr1); if (sta) { - if (sta->flags & WLAN_STA_PS) { + if (test_sta_flags(sta, WLAN_STA_PS)) { /* * The STA is in power save mode, so assume * that this TX packet failed because of that. diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 37f0c2b94ae7..9efeb1f07025 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -79,7 +79,7 @@ void mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata) * * @sta: mes peer link to restart * - * Locking: this function must be called holding sta->plink_lock + * Locking: this function must be called holding sta->lock */ static inline void mesh_plink_fsm_restart(struct sta_info *sta) { @@ -105,7 +105,7 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata, if (!sta) return NULL; - sta->flags |= WLAN_STA_AUTHORIZED; + sta->flags = WLAN_STA_AUTHORIZED; sta->supp_rates[local->hw.conf.channel->band] = rates; return sta; @@ -118,7 +118,7 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata, * * All mesh paths with this peer as next hop will be flushed * - * Locking: the caller must hold sta->plink_lock + * Locking: the caller must hold sta->lock */ static void __mesh_plink_deactivate(struct sta_info *sta) { @@ -139,9 +139,9 @@ static void __mesh_plink_deactivate(struct sta_info *sta) */ void mesh_plink_deactivate(struct sta_info *sta) { - spin_lock_bh(&sta->plink_lock); + spin_lock_bh(&sta->lock); __mesh_plink_deactivate(sta); - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); } static int mesh_plink_frame_tx(struct net_device *dev, @@ -270,10 +270,10 @@ static void mesh_plink_timer(unsigned long data) */ sta = (struct sta_info *) data; - spin_lock_bh(&sta->plink_lock); + spin_lock_bh(&sta->lock); if (sta->ignore_plink_timer) { sta->ignore_plink_timer = false; - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); return; } mpl_dbg("Mesh plink timer for %s fired on state %d\n", @@ -298,7 +298,7 @@ static void mesh_plink_timer(unsigned long data) rand % sta->plink_timeout; ++sta->plink_retries; mod_plink_timer(sta, sta->plink_timeout); - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); mesh_plink_frame_tx(dev, PLINK_OPEN, sta->addr, llid, 0, 0); break; @@ -311,7 +311,7 @@ static void mesh_plink_timer(unsigned long data) reason = cpu_to_le16(MESH_CONFIRM_TIMEOUT); sta->plink_state = PLINK_HOLDING; mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)); - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid, plid, reason); break; @@ -319,10 +319,10 @@ static void mesh_plink_timer(unsigned long data) /* holding timer */ del_timer(&sta->plink_timer); mesh_plink_fsm_restart(sta); - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); break; default: - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); break; } } @@ -344,16 +344,16 @@ int mesh_plink_open(struct sta_info *sta) DECLARE_MAC_BUF(mac); #endif - spin_lock_bh(&sta->plink_lock); + spin_lock_bh(&sta->lock); get_random_bytes(&llid, 2); sta->llid = llid; if (sta->plink_state != PLINK_LISTEN) { - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); return -EBUSY; } sta->plink_state = PLINK_OPN_SNT; mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata)); - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); mpl_dbg("Mesh plink: starting establishment with %s\n", print_mac(mac, sta->addr)); @@ -367,10 +367,10 @@ void mesh_plink_block(struct sta_info *sta) DECLARE_MAC_BUF(mac); #endif - spin_lock_bh(&sta->plink_lock); + spin_lock_bh(&sta->lock); __mesh_plink_deactivate(sta); sta->plink_state = PLINK_BLOCKED; - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); } int mesh_plink_close(struct sta_info *sta) @@ -383,14 +383,14 @@ int mesh_plink_close(struct sta_info *sta) mpl_dbg("Mesh plink: closing link with %s\n", print_mac(mac, sta->addr)); - spin_lock_bh(&sta->plink_lock); + spin_lock_bh(&sta->lock); sta->reason = cpu_to_le16(MESH_LINK_CANCELLED); reason = sta->reason; if (sta->plink_state == PLINK_LISTEN || sta->plink_state == PLINK_BLOCKED) { mesh_plink_fsm_restart(sta); - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); return 0; } else if (sta->plink_state == PLINK_ESTAB) { __mesh_plink_deactivate(sta); @@ -402,7 +402,7 @@ int mesh_plink_close(struct sta_info *sta) sta->plink_state = PLINK_HOLDING; llid = sta->llid; plid = sta->plid; - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); mesh_plink_frame_tx(sta->sdata->dev, PLINK_CLOSE, sta->addr, llid, plid, reason); return 0; @@ -490,7 +490,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, /* avoid warning */ break; } - spin_lock_bh(&sta->plink_lock); + spin_lock_bh(&sta->lock); } else if (!sta) { /* ftype == PLINK_OPEN */ u64 rates; @@ -512,9 +512,9 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, return; } event = OPN_ACPT; - spin_lock_bh(&sta->plink_lock); + spin_lock_bh(&sta->lock); } else { - spin_lock_bh(&sta->plink_lock); + spin_lock_bh(&sta->lock); switch (ftype) { case PLINK_OPEN: if (!mesh_plink_free_count(sdata) || @@ -551,7 +551,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, break; default: mpl_dbg("Mesh plink: unknown frame subtype\n"); - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); rcu_read_unlock(); return; } @@ -568,7 +568,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, switch (event) { case CLS_ACPT: mesh_plink_fsm_restart(sta); - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); break; case OPN_ACPT: sta->plink_state = PLINK_OPN_RCVD; @@ -576,14 +576,14 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, get_random_bytes(&llid, 2); sta->llid = llid; mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata)); - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); mesh_plink_frame_tx(dev, PLINK_OPEN, sta->addr, llid, 0, 0); mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, llid, plid, 0); break; default: - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); break; } break; @@ -603,7 +603,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, sta->ignore_plink_timer = true; llid = sta->llid; - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid, plid, reason); break; @@ -612,7 +612,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, sta->plink_state = PLINK_OPN_RCVD; sta->plid = plid; llid = sta->llid; - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, llid, plid, 0); break; @@ -622,10 +622,10 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, dot11MeshConfirmTimeout(sdata))) sta->ignore_plink_timer = true; - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); break; default: - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); break; } break; @@ -645,13 +645,13 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, sta->ignore_plink_timer = true; llid = sta->llid; - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid, plid, reason); break; case OPN_ACPT: llid = sta->llid; - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, llid, plid, 0); break; @@ -659,12 +659,12 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, del_timer(&sta->plink_timer); sta->plink_state = PLINK_ESTAB; mesh_plink_inc_estab_count(sdata); - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); mpl_dbg("Mesh plink with %s ESTABLISHED\n", print_mac(mac, sta->addr)); break; default: - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); break; } break; @@ -684,7 +684,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, sta->ignore_plink_timer = true; llid = sta->llid; - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid, plid, reason); break; @@ -692,14 +692,14 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, del_timer(&sta->plink_timer); sta->plink_state = PLINK_ESTAB; mesh_plink_inc_estab_count(sdata); - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); mpl_dbg("Mesh plink with %s ESTABLISHED\n", print_mac(mac, sta->addr)); mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, llid, plid, 0); break; default: - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); break; } break; @@ -713,18 +713,18 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, sta->plink_state = PLINK_HOLDING; llid = sta->llid; mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)); - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid, plid, reason); break; case OPN_ACPT: llid = sta->llid; - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, llid, plid, 0); break; default: - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); break; } break; @@ -734,7 +734,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, if (del_timer(&sta->plink_timer)) sta->ignore_plink_timer = 1; mesh_plink_fsm_restart(sta); - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); break; case OPN_ACPT: case CNF_ACPT: @@ -742,19 +742,19 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, case CNF_RJCT: llid = sta->llid; reason = sta->reason; - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid, plid, reason); break; default: - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); } break; default: /* should not get here, PLINK_BLOCKED is dealt with at the * beggining of the function */ - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->lock); break; } diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 108c6fc42fe2..6c4b27be35da 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1241,7 +1241,7 @@ static void ieee80211_sta_process_addba_request(struct net_device *dev, /* examine state machine */ - spin_lock_bh(&sta->ampdu_mlme.ampdu_rx); + spin_lock_bh(&sta->lock); if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_IDLE) { #ifdef CONFIG_MAC80211_HT_DEBUG @@ -1308,7 +1308,7 @@ static void ieee80211_sta_process_addba_request(struct net_device *dev, tid_agg_rx->stored_mpdu_num = 0; status = WLAN_STATUS_SUCCESS; end: - spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx); + spin_unlock_bh(&sta->lock); end_no_lock: ieee80211_send_addba_resp(sta->sdata->dev, sta->addr, tid, @@ -1340,10 +1340,10 @@ static void ieee80211_sta_process_addba_resp(struct net_device *dev, state = &sta->ampdu_mlme.tid_state_tx[tid]; - spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_lock_bh(&sta->lock); if (!(*state & HT_ADDBA_REQUESTED_MSK)) { - spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_unlock_bh(&sta->lock); printk(KERN_DEBUG "state not HT_ADDBA_REQUESTED_MSK:" "%d\n", *state); goto addba_resp_exit; @@ -1351,7 +1351,7 @@ static void ieee80211_sta_process_addba_resp(struct net_device *dev, if (mgmt->u.action.u.addba_resp.dialog_token != sta->ampdu_mlme.tid_tx[tid]->dialog_token) { - spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_unlock_bh(&sta->lock); #ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid); #endif /* CONFIG_MAC80211_HT_DEBUG */ @@ -1375,7 +1375,7 @@ static void ieee80211_sta_process_addba_resp(struct net_device *dev, ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]); } - spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_unlock_bh(&sta->lock); printk(KERN_DEBUG "recipient accepted agg: tid %d \n", tid); } else { printk(KERN_DEBUG "recipient rejected agg: tid %d \n", tid); @@ -1383,7 +1383,7 @@ static void ieee80211_sta_process_addba_resp(struct net_device *dev, sta->ampdu_mlme.addba_req_num[tid]++; /* this will allow the state check in stop_BA_session */ *state = HT_AGG_STATE_OPERATIONAL; - spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_unlock_bh(&sta->lock); ieee80211_stop_tx_ba_session(hw, sta->addr, tid, WLAN_BACK_INITIATOR); } @@ -1453,17 +1453,17 @@ void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *ra, u16 tid, } /* check if TID is in operational state */ - spin_lock_bh(&sta->ampdu_mlme.ampdu_rx); + spin_lock_bh(&sta->lock); if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_OPERATIONAL) { - spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx); + spin_unlock_bh(&sta->lock); rcu_read_unlock(); return; } sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_REQ_STOP_BA_MSK | (initiator << HT_AGG_STATE_INITIATOR_SHIFT); - spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx); + spin_unlock_bh(&sta->lock); /* stop HW Rx aggregation. ampdu_action existence * already verified in session init so we add the BUG_ON */ @@ -1540,10 +1540,10 @@ static void ieee80211_sta_process_delba(struct net_device *dev, ieee80211_sta_stop_rx_ba_session(dev, sta->addr, tid, WLAN_BACK_INITIATOR, 0); else { /* WLAN_BACK_RECIPIENT */ - spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_lock_bh(&sta->lock); sta->ampdu_mlme.tid_state_tx[tid] = HT_AGG_STATE_OPERATIONAL; - spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_unlock_bh(&sta->lock); ieee80211_stop_tx_ba_session(&local->hw, sta->addr, tid, WLAN_BACK_RECIPIENT); } @@ -1580,9 +1580,9 @@ void sta_addba_resp_timer_expired(unsigned long data) state = &sta->ampdu_mlme.tid_state_tx[tid]; /* check if the TID waits for addBA response */ - spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_lock_bh(&sta->lock); if (!(*state & HT_ADDBA_REQUESTED_MSK)) { - spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_unlock_bh(&sta->lock); *state = HT_AGG_STATE_IDLE; printk(KERN_DEBUG "timer expired on tid %d but we are not " "expecting addBA response there", tid); @@ -1593,7 +1593,7 @@ void sta_addba_resp_timer_expired(unsigned long data) /* go through the state check in stop_BA_session */ *state = HT_AGG_STATE_OPERATIONAL; - spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_unlock_bh(&sta->lock); ieee80211_stop_tx_ba_session(hw, temp_sta->addr, tid, WLAN_BACK_INITIATOR); @@ -1984,8 +1984,8 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, * to between the sta_info_alloc() and sta_info_insert() above. */ - sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP | - WLAN_STA_AUTHORIZED; + set_sta_flags(sta, WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP | + WLAN_STA_AUTHORIZED); rates = 0; basic_rates = 0; @@ -2044,7 +2044,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, rate_control_rate_init(sta, local); if (elems.wmm_param) { - sta->flags |= WLAN_STA_WME; + set_sta_flags(sta, WLAN_STA_WME); rcu_read_unlock(); ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param, elems.wmm_param_len); @@ -4237,7 +4237,7 @@ struct sta_info *ieee80211_ibss_add_sta(struct net_device *dev, if (!sta) return NULL; - sta->flags |= WLAN_STA_AUTHORIZED; + set_sta_flags(sta, WLAN_STA_AUTHORIZED); sta->supp_rates[local->hw.conf.channel->band] = sdata->u.sta.supp_rates_bits[local->hw.conf.channel->band]; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index e8b89c89e875..b399e09ec7aa 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -479,7 +479,7 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx) ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL && (rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)) && rx->sdata->vif.type != IEEE80211_IF_TYPE_IBSS && - (!rx->sta || !(rx->sta->flags & WLAN_STA_ASSOC)))) { + (!rx->sta || !test_sta_flags(rx->sta, WLAN_STA_ASSOC)))) { if ((!(rx->fc & IEEE80211_FCTL_FROMDS) && !(rx->fc & IEEE80211_FCTL_TODS) && (rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) @@ -630,8 +630,7 @@ static void ap_sta_ps_start(struct net_device *dev, struct sta_info *sta) if (sdata->bss) atomic_inc(&sdata->bss->num_sta_ps); - sta->flags |= WLAN_STA_PS; - sta->flags &= ~WLAN_STA_PSPOLL; + set_and_clear_sta_flags(sta, WLAN_STA_PS, WLAN_STA_PSPOLL); #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG printk(KERN_DEBUG "%s: STA %s aid %d enters power save mode\n", dev->name, print_mac(mac, sta->addr), sta->aid); @@ -652,7 +651,7 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta) if (sdata->bss) atomic_dec(&sdata->bss->num_sta_ps); - sta->flags &= ~(WLAN_STA_PS | WLAN_STA_PSPOLL); + clear_sta_flags(sta, WLAN_STA_PS | WLAN_STA_PSPOLL); if (!skb_queue_empty(&sta->ps_tx_buf)) sta_info_clear_tim_bit(sta); @@ -727,9 +726,10 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) if (!(rx->fc & IEEE80211_FCTL_MOREFRAGS)) { /* Change STA power saving mode only in the end of a frame * exchange sequence */ - if ((sta->flags & WLAN_STA_PS) && !(rx->fc & IEEE80211_FCTL_PM)) + if (test_sta_flags(sta, WLAN_STA_PS) && + !(rx->fc & IEEE80211_FCTL_PM)) rx->sent_ps_buffered += ap_sta_ps_end(dev, sta); - else if (!(sta->flags & WLAN_STA_PS) && + else if (!test_sta_flags(sta, WLAN_STA_PS) && (rx->fc & IEEE80211_FCTL_PM)) ap_sta_ps_start(dev, sta); } @@ -983,7 +983,7 @@ ieee80211_rx_h_ps_poll(struct ieee80211_rx_data *rx) * Tell TX path to send one frame even though the STA may * still remain is PS mode after this frame exchange. */ - rx->sta->flags |= WLAN_STA_PSPOLL; + set_sta_flags(rx->sta, WLAN_STA_PSPOLL); #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG printk(KERN_DEBUG "STA %s aid %d: PS Poll (entries after %d)\n", @@ -1046,7 +1046,8 @@ ieee80211_rx_h_remove_qos_control(struct ieee80211_rx_data *rx) static int ieee80211_802_1x_port_control(struct ieee80211_rx_data *rx) { - if (unlikely(!rx->sta || !(rx->sta->flags & WLAN_STA_AUTHORIZED))) { + if (unlikely(!rx->sta || + !test_sta_flags(rx->sta, WLAN_STA_AUTHORIZED))) { #ifdef CONFIG_MAC80211_DEBUG if (net_ratelimit()) printk(KERN_DEBUG "%s: dropped frame " diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 631943e8af8b..baf5e4746884 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -202,14 +202,12 @@ void sta_info_destroy(struct sta_info *sta) dev_kfree_skb_any(skb); for (i = 0; i < STA_TID_NUM; i++) { - spin_lock_bh(&sta->ampdu_mlme.ampdu_rx); + spin_lock_bh(&sta->lock); if (sta->ampdu_mlme.tid_rx[i]) del_timer_sync(&sta->ampdu_mlme.tid_rx[i]->session_timer); - spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx); - spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); if (sta->ampdu_mlme.tid_tx[i]) del_timer_sync(&sta->ampdu_mlme.tid_tx[i]->addba_resp_timer); - spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + spin_unlock_bh(&sta->lock); } __sta_info_free(local, sta); @@ -236,6 +234,8 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, if (!sta) return NULL; + spin_lock_init(&sta->lock); + memcpy(sta->addr, addr, ETH_ALEN); sta->local = local; sta->sdata = sdata; @@ -249,8 +249,6 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, return NULL; } - spin_lock_init(&sta->ampdu_mlme.ampdu_rx); - spin_lock_init(&sta->ampdu_mlme.ampdu_tx); for (i = 0; i < STA_TID_NUM; i++) { /* timer_to_tid must be initialized with identity mapping to * enable session_timer's data differentiation. refer to @@ -276,7 +274,6 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, #ifdef CONFIG_MAC80211_MESH sta->plink_state = PLINK_LISTEN; - spin_lock_init(&sta->plink_lock); init_timer(&sta->plink_timer); #endif @@ -437,8 +434,7 @@ void __sta_info_unlink(struct sta_info **sta) list_del(&(*sta)->list); - if ((*sta)->flags & WLAN_STA_PS) { - (*sta)->flags &= ~WLAN_STA_PS; + if (test_and_clear_sta_flags(*sta, WLAN_STA_PS)) { if (sdata->bss) atomic_dec(&sdata->bss->num_sta_ps); __sta_info_clear_tim_bit(sdata->bss, *sta); diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index f8c95bc9659c..97a61c39ad90 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -129,23 +129,19 @@ enum plink_state { * * @tid_state_rx: TID's state in Rx session state machine. * @tid_rx: aggregation info for Rx per TID - * @ampdu_rx: for locking sections in aggregation Rx flow * @tid_state_tx: TID's state in Tx session state machine. * @tid_tx: aggregation info for Tx per TID * @addba_req_num: number of times addBA request has been sent. - * @ampdu_tx: for locking sectionsi in aggregation Tx flow * @dialog_token_allocator: dialog token enumerator for each new session; */ struct sta_ampdu_mlme { /* rx */ u8 tid_state_rx[STA_TID_NUM]; struct tid_ampdu_rx *tid_rx[STA_TID_NUM]; - spinlock_t ampdu_rx; /* tx */ u8 tid_state_tx[STA_TID_NUM]; struct tid_ampdu_tx *tid_tx[STA_TID_NUM]; u8 addba_req_num[STA_TID_NUM]; - spinlock_t ampdu_tx; u8 dialog_token_allocator; }; @@ -177,6 +173,8 @@ struct sta_ampdu_mlme { * @rx_bytes: Number of bytes received from this STA * @supp_rates: Bitmap of supported rates (per band) * @ht_info: HT capabilities of this STA + * @lock: used for locking all fields that require locking, see comments + * in the header file. */ struct sta_info { /* General information, mostly static */ @@ -187,6 +185,7 @@ struct sta_info { struct ieee80211_key *key; struct rate_control_ref *rate_ctrl; void *rate_ctrl_priv; + spinlock_t lock; struct ieee80211_ht_info ht_info; u64 supp_rates[IEEE80211_NUM_BANDS]; u8 addr[ETH_ALEN]; @@ -199,7 +198,7 @@ struct sta_info { */ u8 pin_status; - /* frequently updated information, needs locking? */ + /* frequently updated information, locked with lock spinlock */ u32 flags; /* @@ -251,7 +250,7 @@ struct sta_info { int channel_use_raw; /* - * Aggregation information, comes with own locking. + * Aggregation information, locked with lock. */ struct sta_ampdu_mlme ampdu_mlme; u8 timer_to_tid[STA_TID_NUM]; /* identity mapping to ID timers */ @@ -270,9 +269,6 @@ struct sta_info { enum plink_state plink_state; u32 plink_timeout; struct timer_list plink_timer; - spinlock_t plink_lock; /* For peer_state reads / updates and other - updates in the structure. Ensures robust - transitions for the peerlink FSM */ #endif #ifdef CONFIG_MAC80211_DEBUGFS @@ -299,6 +295,64 @@ static inline enum plink_state sta_plink_state(struct sta_info *sta) return PLINK_LISTEN; } +static inline void set_sta_flags(struct sta_info *sta, const u32 flags) +{ + spin_lock_bh(&sta->lock); + sta->flags |= flags; + spin_unlock_bh(&sta->lock); +} + +static inline void clear_sta_flags(struct sta_info *sta, const u32 flags) +{ + spin_lock_bh(&sta->lock); + sta->flags &= ~flags; + spin_unlock_bh(&sta->lock); +} + +static inline void set_and_clear_sta_flags(struct sta_info *sta, + const u32 set, const u32 clear) +{ + spin_lock_bh(&sta->lock); + sta->flags |= set; + sta->flags &= ~clear; + spin_unlock_bh(&sta->lock); +} + +static inline u32 test_sta_flags(struct sta_info *sta, const u32 flags) +{ + u32 ret; + + spin_lock_bh(&sta->lock); + ret = sta->flags & flags; + spin_unlock_bh(&sta->lock); + + return ret; +} + +static inline u32 test_and_clear_sta_flags(struct sta_info *sta, + const u32 flags) +{ + u32 ret; + + spin_lock_bh(&sta->lock); + ret = sta->flags & flags; + sta->flags &= ~flags; + spin_unlock_bh(&sta->lock); + + return ret; +} + +static inline u32 get_sta_flags(struct sta_info *sta) +{ + u32 ret; + + spin_lock_bh(&sta->lock); + ret = sta->flags; + spin_unlock_bh(&sta->lock); + + return ret; +} + /* Maximum number of concurrently registered stations */ #define MAX_STA_COUNT 2007 diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 3a03d7807c39..5f31a6233e13 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -256,7 +256,7 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx) if (tx->flags & IEEE80211_TX_PS_BUFFERED) return TX_CONTINUE; - sta_flags = tx->sta ? tx->sta->flags : 0; + sta_flags = tx->sta ? get_sta_flags(tx->sta) : 0; if (likely(tx->flags & IEEE80211_TX_UNICAST)) { if (unlikely(!(sta_flags & WLAN_STA_ASSOC) && @@ -391,6 +391,7 @@ static ieee80211_tx_result ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) { struct sta_info *sta = tx->sta; + u32 staflags; DECLARE_MAC_BUF(mac); if (unlikely(!sta || @@ -398,8 +399,10 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) (tx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP))) return TX_CONTINUE; - if (unlikely((sta->flags & WLAN_STA_PS) && - !(sta->flags & WLAN_STA_PSPOLL))) { + staflags = get_sta_flags(sta); + + if (unlikely((staflags & WLAN_STA_PS) && + !(staflags & WLAN_STA_PSPOLL))) { struct ieee80211_tx_packet_data *pkt_data; #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG printk(KERN_DEBUG "STA %s aid %d: PS buffer (entries " @@ -430,13 +433,13 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) return TX_QUEUED; } #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - else if (unlikely(sta->flags & WLAN_STA_PS)) { + else if (unlikely(test_sta_flags(sta, WLAN_STA_PS))) { printk(KERN_DEBUG "%s: STA %s in PS mode, but pspoll " "set -> send frame\n", tx->dev->name, print_mac(mac, sta->addr)); } #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ - sta->flags &= ~WLAN_STA_PSPOLL; + clear_sta_flags(sta, WLAN_STA_PSPOLL); return TX_CONTINUE; } @@ -697,7 +700,7 @@ ieee80211_tx_h_misc(struct ieee80211_tx_data *tx) if (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) && (tx->rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) && tx->sdata->bss_conf.use_short_preamble && - (!tx->sta || (tx->sta->flags & WLAN_STA_SHORT_PREAMBLE))) { + (!tx->sta || test_sta_flags(tx->sta, WLAN_STA_SHORT_PREAMBLE))) { tx->control->flags |= IEEE80211_TXCTL_SHORT_PREAMBLE; } @@ -1025,10 +1028,8 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx, if (!tx->sta) control->flags |= IEEE80211_TXCTL_CLEAR_PS_FILT; - else if (tx->sta->flags & WLAN_STA_CLEAR_PS_FILT) { + else if (test_and_clear_sta_flags(tx->sta, WLAN_STA_CLEAR_PS_FILT)) control->flags |= IEEE80211_TXCTL_CLEAR_PS_FILT; - tx->sta->flags &= ~WLAN_STA_CLEAR_PS_FILT; - } hdrlen = ieee80211_get_hdrlen(tx->fc); if (skb->len > hdrlen + sizeof(rfc1042_header) + 2) { @@ -1486,7 +1487,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, rcu_read_lock(); sta = sta_info_get(local, hdr.addr1); if (sta) - sta_flags = sta->flags; + sta_flags = get_sta_flags(sta); rcu_read_unlock(); } -- cgit v1.2.3 From 566bfe5a8bcde13188a356f77666f8115813cf31 Mon Sep 17 00:00:00 2001 From: Bruno Randolf Date: Thu, 8 May 2008 19:15:40 +0200 Subject: mac80211: use hardware flags for signal/noise units trying to clean up the signal/noise code. the previous code in mac80211 had confusing names for the related variables, did not have much definition of what units of signal and noise were provided and used implicit mechanisms from the wireless extensions. this patch introduces hardware capability flags to let the hardware specify clearly if it can provide signal and noise level values and which units it can provide. this also anticipates possible new units like RCPI in the future. for signal: IEEE80211_HW_SIGNAL_UNSPEC - unspecified, unknown, hw specific IEEE80211_HW_SIGNAL_DB - dB difference to unspecified reference point IEEE80211_HW_SIGNAL_DBM - dBm, difference to 1mW for noise we currently only have dBm: IEEE80211_HW_NOISE_DBM - dBm, difference to 1mW if IEEE80211_HW_SIGNAL_UNSPEC or IEEE80211_HW_SIGNAL_DB is used the driver has to provide the maximum value (max_signal) it reports in order for applications to make sense of the signal values. i tried my best to find out for each driver what it can provide and update it but i'm not sure (?) for some of them and used the more conservative guess in doubt. this can be fixed easily after this patch has been merged by changing the hardware flags of the driver. DRIVER SIGNAL MAX NOISE QUAL ----------------------------------------------------------------- adm8211 unspec(?) 100 n/a missing at76_usb unspec(?) (?) unused missing ath5k dBm dBm percent rssi b43legacy dBm dBm percent jssi(?) b43 dBm dBm percent jssi(?) iwl-3945 dBm dBm percent snr+more iwl-4965 dBm dBm percent snr+more p54 unspec 127 n/a missing rt2x00 dBm n/a percent rssi+tx/rx frame success rt2400 dBm n/a rt2500pci dBm n/a rt2500usb dBm n/a rt61pci dBm n/a rt73usb dBm n/a rtl8180 unspec(?) 65 n/a (?) rtl8187 unspec(?) 65 (?) noise(?) zd1211 dB(?) 100 n/a percent drivers/net/wireless/ath5k/base.c: Changes-licensed-under: 3-Clause-BSD Signed-off-by: Bruno Randolf Signed-off-by: John W. Linville --- drivers/net/wireless/adm8211.c | 7 +++-- drivers/net/wireless/ath5k/base.c | 23 +++----------- drivers/net/wireless/b43/main.c | 8 ++--- drivers/net/wireless/b43/xmit.c | 5 ++- drivers/net/wireless/b43legacy/main.c | 7 ++--- drivers/net/wireless/b43legacy/xmit.c | 4 +-- drivers/net/wireless/iwlwifi/iwl-3945.c | 18 +++++------ drivers/net/wireless/iwlwifi/iwl-4965.c | 12 ++++---- drivers/net/wireless/iwlwifi/iwl-core.c | 16 +++------- drivers/net/wireless/iwlwifi/iwl3945-base.c | 15 +++------ drivers/net/wireless/p54/p54common.c | 7 +++-- drivers/net/wireless/rt2x00/rt2400pci.c | 5 ++- drivers/net/wireless/rt2x00/rt2500pci.c | 6 ++-- drivers/net/wireless/rt2x00/rt2500usb.c | 6 ++-- drivers/net/wireless/rt2x00/rt2x00dev.c | 4 +-- drivers/net/wireless/rt2x00/rt61pci.c | 5 ++- drivers/net/wireless/rt2x00/rt73usb.c | 5 ++- drivers/net/wireless/rtl8180_dev.c | 9 +++--- drivers/net/wireless/rtl8187_dev.c | 10 +++--- drivers/net/wireless/zd1211rw/zd_mac.c | 12 ++++---- include/net/mac80211.h | 47 +++++++++++++++++++++-------- net/ieee80211/ieee80211_rx.c | 2 +- net/mac80211/debugfs_sta.c | 2 +- net/mac80211/ieee80211_i.h | 2 +- net/mac80211/main.c | 10 +++--- net/mac80211/mlme.c | 12 ++++---- net/mac80211/rx.c | 4 +-- net/mac80211/sta_info.h | 2 +- net/mac80211/wext.c | 28 ++++++++++++----- 29 files changed, 148 insertions(+), 145 deletions(-) (limited to 'net/mac80211/mlme.c') diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index d93a1de77eb0..7af5d8851f67 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -445,9 +445,9 @@ static void adm8211_interrupt_rci(struct ieee80211_hw *dev) struct ieee80211_rx_status rx_status = {0}; if (priv->pdev->revision < ADM8211_REV_CA) - rx_status.ssi = rssi; + rx_status.signal = rssi; else - rx_status.ssi = 100 - rssi; + rx_status.signal = 100 - rssi; rx_status.rate_idx = rate; @@ -1893,9 +1893,10 @@ static int __devinit adm8211_probe(struct pci_dev *pdev, dev->extra_tx_headroom = sizeof(struct adm8211_tx_hdr); /* dev->flags = IEEE80211_HW_RX_INCLUDES_FCS in promisc mode */ + dev->flags = IEEE80211_HW_SIGNAL_UNSPEC; dev->channel_change_time = 1000; - dev->max_rssi = 100; /* FIXME: find better value */ + dev->max_signal = 100; /* FIXME: find better value */ dev->queues = 1; /* ADM8211C supports more, maybe ADM8211B too */ diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index 3201c1604340..dd8adaddd7a0 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -458,13 +458,11 @@ ath5k_pci_probe(struct pci_dev *pdev, /* Initialize driver private data */ SET_IEEE80211_DEV(hw, &pdev->dev); - hw->flags = IEEE80211_HW_RX_INCLUDES_FCS; + hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | + IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_NOISE_DBM; hw->extra_tx_headroom = 2; hw->channel_change_time = 5000; - /* these names are misleading */ - hw->max_rssi = -110; /* signal in dBm */ - hw->max_noise = -110; /* noise in dBm */ - hw->max_signal = 100; /* we will provide a percentage based on rssi */ sc = hw->priv; sc->hw = hw; sc->pdev = pdev; @@ -1893,20 +1891,9 @@ accept: rxs.freq = sc->curchan->center_freq; rxs.band = sc->curband->band; - /* - * signal quality: - * the names here are misleading and the usage of these - * values by iwconfig makes it even worse - */ - /* noise floor in dBm, from the last noise calibration */ rxs.noise = sc->ah->ah_noise_floor; - /* signal level in dBm */ - rxs.ssi = rxs.noise + rs.rs_rssi; - /* - * "signal" is actually displayed as Link Quality by iwconfig - * we provide a percentage based on rssi (assuming max rssi 64) - */ - rxs.signal = rs.rs_rssi * 100 / 64; + rxs.signal = rxs.noise + rs.rs_rssi; + rxs.qual = rs.rs_rssi * 100 / 64; rxs.antenna = rs.rs_antenna; rxs.rate_idx = ath5k_hw_to_driver_rix(sc, rs.rs_rate); diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 7c23aa8705c2..fc23ba5309bd 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -4466,10 +4466,10 @@ static int b43_wireless_init(struct ssb_device *dev) /* fill hw info */ hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | - IEEE80211_HW_RX_INCLUDES_FCS; - hw->max_signal = 100; - hw->max_rssi = -110; - hw->max_noise = -110; + IEEE80211_HW_RX_INCLUDES_FCS | + IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_NOISE_DBM; + hw->queues = b43_modparam_qos ? 4 : 1; SET_IEEE80211_DEV(hw, dev->dev); if (is_valid_ether_addr(sprom->et1mac)) diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index 88491947a209..afce9338d83a 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c @@ -581,12 +581,11 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) // and also find out what the maximum possible value is. // Fill status.ssi and status.signal fields. } else { - status.ssi = b43_rssi_postprocess(dev, rxhdr->jssi, + status.signal = b43_rssi_postprocess(dev, rxhdr->jssi, (phystat0 & B43_RX_PHYST0_OFDM), (phystat0 & B43_RX_PHYST0_GAINCTL), (phystat3 & B43_RX_PHYST3_TRSTATE)); - /* the next line looks wrong, but is what mac80211 wants */ - status.signal = (rxhdr->jssi * 100) / B43_RX_MAX_SSI; + status.qual = (rxhdr->jssi * 100) / B43_RX_MAX_SSI; } if (phystat0 & B43_RX_PHYST0_OFDM) diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index d3820dce3c43..7755c59e0803 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -3718,10 +3718,9 @@ static int b43legacy_wireless_init(struct ssb_device *dev) /* fill hw info */ hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | - IEEE80211_HW_RX_INCLUDES_FCS; - hw->max_signal = 100; - hw->max_rssi = -110; - hw->max_noise = -110; + IEEE80211_HW_RX_INCLUDES_FCS | + IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_NOISE_DBM; hw->queues = 1; /* FIXME: hardware has more queues */ SET_IEEE80211_DEV(hw, dev->dev); if (is_valid_ether_addr(sprom->et1mac)) diff --git a/drivers/net/wireless/b43legacy/xmit.c b/drivers/net/wireless/b43legacy/xmit.c index fc83dab6e2c7..bed9e041d6c5 100644 --- a/drivers/net/wireless/b43legacy/xmit.c +++ b/drivers/net/wireless/b43legacy/xmit.c @@ -532,12 +532,12 @@ void b43legacy_rx(struct b43legacy_wldev *dev, } } - status.ssi = b43legacy_rssi_postprocess(dev, jssi, + status.signal = b43legacy_rssi_postprocess(dev, jssi, (phystat0 & B43legacy_RX_PHYST0_OFDM), (phystat0 & B43legacy_RX_PHYST0_GAINCTL), (phystat3 & B43legacy_RX_PHYST3_TRSTATE)); status.noise = dev->stats.link_noise; - status.signal = (jssi * 100) / B43legacy_RX_MAX_SSI; + status.qual = (jssi * 100) / B43legacy_RX_MAX_SSI; /* change to support A PHY */ if (phystat0 & B43legacy_RX_PHYST0_OFDM) status.rate_idx = b43legacy_plcp_get_bitrate_idx_ofdm(plcp, false); diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 8464397f7816..d7beeff2642c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -520,7 +520,7 @@ static void iwl3945_add_radiotap(struct iwl3945_priv *priv, { /* First cache any information we need before we overwrite * the information provided in the skb from the hardware */ - s8 signal = stats->ssi; + s8 signal = stats->signal; s8 noise = 0; int rate = stats->rate_idx; u64 tsf = stats->mactime; @@ -693,7 +693,7 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv, } /* Convert 3945's rssi indicator to dBm */ - rx_status.ssi = rx_stats->rssi - IWL_RSSI_OFFSET; + rx_status.signal = rx_stats->rssi - IWL_RSSI_OFFSET; /* Set default noise value to -127 */ if (priv->last_rx_noise == 0) @@ -712,21 +712,21 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv, * Calculate rx_status.signal (quality indicator in %) based on SNR. */ if (rx_stats_noise_diff) { snr = rx_stats_sig_avg / rx_stats_noise_diff; - rx_status.noise = rx_status.ssi - + rx_status.noise = rx_status.signal - iwl3945_calc_db_from_ratio(snr); - rx_status.signal = iwl3945_calc_sig_qual(rx_status.ssi, + rx_status.qual = iwl3945_calc_sig_qual(rx_status.signal, rx_status.noise); /* If noise info not available, calculate signal quality indicator (%) * using just the dBm signal level. */ } else { rx_status.noise = priv->last_rx_noise; - rx_status.signal = iwl3945_calc_sig_qual(rx_status.ssi, 0); + rx_status.qual = iwl3945_calc_sig_qual(rx_status.signal, 0); } IWL_DEBUG_STATS("Rssi %d noise %d qual %d sig_avg %d noise_diff %d\n", - rx_status.ssi, rx_status.noise, rx_status.signal, + rx_status.signal, rx_status.noise, rx_status.qual, rx_stats_sig_avg, rx_stats_noise_diff); header = (struct ieee80211_hdr *)IWL_RX_DATA(pkt); @@ -736,8 +736,8 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv, IWL_DEBUG_STATS_LIMIT("[%c] %d RSSI:%d Signal:%u, Noise:%u, Rate:%u\n", network_packet ? '*' : ' ', le16_to_cpu(rx_hdr->channel), - rx_status.ssi, rx_status.ssi, - rx_status.ssi, rx_status.rate_idx); + rx_status.signal, rx_status.signal, + rx_status.noise, rx_status.rate_idx); #ifdef CONFIG_IWL3945_DEBUG if (iwl3945_debug_level & (IWL_DL_RX)) @@ -748,7 +748,7 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv, if (network_packet) { priv->last_beacon_time = le32_to_cpu(rx_end->beacon_timestamp); priv->last_tsf = le64_to_cpu(rx_end->timestamp); - priv->last_rx_rssi = rx_status.ssi; + priv->last_rx_rssi = rx_status.signal; priv->last_rx_noise = rx_status.noise; } diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index b7036e011457..45cbd7789bd0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2362,7 +2362,7 @@ static void iwl4965_add_radiotap(struct iwl_priv *priv, struct ieee80211_rx_status *stats, u32 ampdu_status) { - s8 signal = stats->ssi; + s8 signal = stats->signal; s8 noise = 0; int rate = stats->rate_idx; u64 tsf = stats->mactime; @@ -2963,7 +2963,7 @@ static void iwl4965_rx_reply_rx(struct iwl_priv *priv, priv->ucode_beacon_time = le32_to_cpu(rx_start->beacon_time_stamp); /* Find max signal strength (dBm) among 3 antenna/receiver chains */ - rx_status.ssi = iwl4965_calc_rssi(priv, rx_start); + rx_status.signal = iwl4965_calc_rssi(priv, rx_start); /* Meaningful noise values are available only from beacon statistics, * which are gathered only when associated, and indicate noise @@ -2972,11 +2972,11 @@ static void iwl4965_rx_reply_rx(struct iwl_priv *priv, if (iwl_is_associated(priv) && !test_bit(STATUS_SCANNING, &priv->status)) { rx_status.noise = priv->last_rx_noise; - rx_status.signal = iwl4965_calc_sig_qual(rx_status.ssi, + rx_status.qual = iwl4965_calc_sig_qual(rx_status.signal, rx_status.noise); } else { rx_status.noise = IWL_NOISE_MEAS_NOT_AVAILABLE; - rx_status.signal = iwl4965_calc_sig_qual(rx_status.ssi, 0); + rx_status.qual = iwl4965_calc_sig_qual(rx_status.signal, 0); } /* Reset beacon noise level if not associated. */ @@ -2988,7 +2988,7 @@ static void iwl4965_rx_reply_rx(struct iwl_priv *priv, iwl4965_dbg_report_frame(priv, pkt, header, 1); IWL_DEBUG_STATS_LIMIT("Rssi %d, noise %d, qual %d, TSF %llu\n", - rx_status.ssi, rx_status.noise, rx_status.signal, + rx_status.signal, rx_status.noise, rx_status.signal, (unsigned long long)rx_status.mactime); @@ -3000,7 +3000,7 @@ static void iwl4965_rx_reply_rx(struct iwl_priv *priv, network_packet = iwl4965_is_network_packet(priv, header); if (network_packet) { - priv->last_rx_rssi = rx_status.ssi; + priv->last_rx_rssi = rx_status.signal; priv->last_beacon_time = priv->ucode_beacon_time; priv->last_tsf = le64_to_cpu(rx_start->timestamp); } diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 27e56b89d940..d3cbad2bf877 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -746,18 +746,10 @@ static void iwlcore_init_hw(struct iwl_priv *priv) struct ieee80211_hw *hw = priv->hw; hw->rate_control_algorithm = "iwl-4965-rs"; - /* Tell mac80211 and its clients (e.g. Wireless Extensions) - * the range of signal quality values that we'll provide. - * Negative values for level/noise indicate that we'll provide dBm. - * For WE, at least, non-0 values here *enable* display of values - * in app (iwconfig). */ - hw->max_rssi = -20; /* signal level, negative indicates dBm */ - hw->max_noise = -20; /* noise level, negative indicates dBm */ - hw->max_signal = 100; /* link quality indication (%) */ - - /* Tell mac80211 our Tx characteristics */ - hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE; - + /* Tell mac80211 our characteristics */ + hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | + IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_NOISE_DBM; /* Default value; 4 EDCA QOS priorities */ hw->queues = 4; #ifdef CONFIG_IWL4965_HT diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 4baa185ba500..c1234ff4fc98 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -8029,17 +8029,10 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e priv->ibss_beacon = NULL; - /* Tell mac80211 and its clients (e.g. Wireless Extensions) - * the range of signal quality values that we'll provide. - * Negative values for level/noise indicate that we'll provide dBm. - * For WE, at least, non-0 values here *enable* display of values - * in app (iwconfig). */ - hw->max_rssi = -20; /* signal level, negative indicates dBm */ - hw->max_noise = -20; /* noise level, negative indicates dBm */ - hw->max_signal = 100; /* link quality indication (%) */ - - /* Tell mac80211 our Tx characteristics */ - hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE; + /* Tell mac80211 our characteristics */ + hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | + IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_NOISE_DBM; /* 4 EDCA QOS priorities */ hw->queues = 4; diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 33d608a60d79..9cbef5bce0f6 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -355,7 +355,7 @@ static void p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) struct ieee80211_rx_status rx_status = {0}; u16 freq = le16_to_cpu(hdr->freq); - rx_status.ssi = hdr->rssi; + rx_status.signal = hdr->rssi; /* XX correct? */ rx_status.rate_idx = hdr->rate & 0xf; rx_status.freq = freq; @@ -1000,9 +1000,10 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) skb_queue_head_init(&priv->tx_queue); dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &band_2GHz; dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | /* not sure */ - IEEE80211_HW_RX_INCLUDES_FCS; + IEEE80211_HW_RX_INCLUDES_FCS | + IEEE80211_HW_SIGNAL_UNSPEC; dev->channel_change_time = 1000; /* TODO: find actual value */ - dev->max_rssi = 127; + dev->max_signal = 127; priv->tx_stats[0].limit = 5; dev->queues = 1; diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 247fbbfb0f2b..afa565c63621 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1361,10 +1361,9 @@ static void rt2400pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) /* * Initialize all hw fields. */ - rt2x00dev->hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING; + rt2x00dev->hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | + IEEE80211_HW_SIGNAL_DBM; rt2x00dev->hw->extra_tx_headroom = 0; - rt2x00dev->hw->max_signal = MAX_SIGNAL; - rt2x00dev->hw->max_rssi = MAX_RX_SSI; rt2x00dev->hw->queues = 2; SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev); diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 0d53c75d55dd..c06f1b5e5887 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1680,10 +1680,10 @@ static void rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) /* * Initialize all hw fields. */ - rt2x00dev->hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING; + rt2x00dev->hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | + IEEE80211_HW_SIGNAL_DBM; + rt2x00dev->hw->extra_tx_headroom = 0; - rt2x00dev->hw->max_signal = MAX_SIGNAL; - rt2x00dev->hw->max_rssi = MAX_RX_SSI; rt2x00dev->hw->queues = 2; SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev); diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 80b34d47114a..88bafdf8f0fa 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1587,10 +1587,10 @@ static void rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) rt2x00dev->hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | IEEE80211_HW_RX_INCLUDES_FCS | - IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING; + IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | + IEEE80211_HW_SIGNAL_DBM; + rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE; - rt2x00dev->hw->max_signal = MAX_SIGNAL; - rt2x00dev->hw->max_rssi = MAX_RX_SSI; rt2x00dev->hw->queues = 2; SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_usb(rt2x00dev)->dev); diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 9929b15e28ba..f51a50b31e16 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -600,9 +600,9 @@ void rt2x00lib_rxdone(struct queue_entry *entry, rt2x00dev->link.qual.rx_success++; rx_status->rate_idx = idx; - rx_status->signal = + rx_status->qual = rt2x00lib_calculate_link_signal(rt2x00dev, rxdesc->rssi); - rx_status->ssi = rxdesc->rssi; + rx_status->signal = rxdesc->rssi; rx_status->flag = rxdesc->flags; rx_status->antenna = rt2x00dev->link.ant.active.rx; diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 98af4d26583d..eaf23b908772 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2245,10 +2245,9 @@ static void rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) */ rt2x00dev->hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | - IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING; + IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | + IEEE80211_HW_SIGNAL_DBM; rt2x00dev->hw->extra_tx_headroom = 0; - rt2x00dev->hw->max_signal = MAX_SIGNAL; - rt2x00dev->hw->max_rssi = MAX_RX_SSI; rt2x00dev->hw->queues = 4; SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev); diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 351d95c4f50d..51c5575ed02f 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1830,10 +1830,9 @@ static void rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) */ rt2x00dev->hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | - IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING; + IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | + IEEE80211_HW_SIGNAL_DBM; rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE; - rt2x00dev->hw->max_signal = MAX_SIGNAL; - rt2x00dev->hw->max_rssi = MAX_RX_SSI; rt2x00dev->hw->queues = 4; SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_usb(rt2x00dev)->dev); diff --git a/drivers/net/wireless/rtl8180_dev.c b/drivers/net/wireless/rtl8180_dev.c index c181f23e930d..c220998cee65 100644 --- a/drivers/net/wireless/rtl8180_dev.c +++ b/drivers/net/wireless/rtl8180_dev.c @@ -132,8 +132,8 @@ static void rtl8180_handle_rx(struct ieee80211_hw *dev) rx_status.antenna = (flags2 >> 15) & 1; /* TODO: improve signal/rssi reporting */ - rx_status.signal = flags2 & 0xFF; - rx_status.ssi = (flags2 >> 8) & 0x7F; + rx_status.qual = flags2 & 0xFF; + rx_status.signal = (flags2 >> 8) & 0x7F; /* XXX: is this correct? */ rx_status.rate_idx = (flags >> 20) & 0xF; rx_status.freq = dev->conf.channel->center_freq; @@ -894,9 +894,10 @@ static int __devinit rtl8180_probe(struct pci_dev *pdev, dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band; dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | - IEEE80211_HW_RX_INCLUDES_FCS; + IEEE80211_HW_RX_INCLUDES_FCS | + IEEE80211_HW_SIGNAL_UNSPEC; dev->queues = 1; - dev->max_rssi = 65; + dev->max_signal = 65; reg = rtl818x_ioread32(priv, &priv->map->TX_CONF); reg &= RTL818X_TX_CONF_HWVER_MASK; diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c index d5787b37e1fb..e14c84248686 100644 --- a/drivers/net/wireless/rtl8187_dev.c +++ b/drivers/net/wireless/rtl8187_dev.c @@ -261,8 +261,8 @@ static void rtl8187_rx_cb(struct urb *urb) } rx_status.antenna = (hdr->signal >> 7) & 1; - rx_status.signal = 64 - min(hdr->noise, (u8)64); - rx_status.ssi = signal; + rx_status.qual = 64 - min(hdr->noise, (u8)64); + rx_status.signal = signal; rx_status.rate_idx = rate; rx_status.freq = dev->conf.channel->center_freq; rx_status.band = dev->conf.channel->band; @@ -740,11 +740,11 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, priv->mode = IEEE80211_IF_TYPE_MNTR; dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | - IEEE80211_HW_RX_INCLUDES_FCS; + IEEE80211_HW_RX_INCLUDES_FCS | + IEEE80211_HW_SIGNAL_UNSPEC; dev->extra_tx_headroom = sizeof(struct rtl8187_tx_hdr); dev->queues = 1; - dev->max_rssi = 65; - dev->max_signal = 64; + dev->max_signal = 65; eeprom.data = dev; eeprom.register_read = rtl8187_eeprom_register_read; diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index ee4331229f1f..0c736735e217 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -638,7 +638,7 @@ static int filter_ack(struct ieee80211_hw *hw, struct ieee80211_hdr *rx_hdr, memset(&status, 0, sizeof(status)); status.flags = IEEE80211_TX_STATUS_ACK; - status.ack_signal = stats->ssi; + status.ack_signal = stats->signal; __skb_unlink(skb, q); tx_status(hw, skb, &status, 1); goto out; @@ -691,8 +691,8 @@ int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length) stats.freq = zd_channels[_zd_chip_get_channel(&mac->chip) - 1].center_freq; stats.band = IEEE80211_BAND_2GHZ; - stats.ssi = status->signal_strength; - stats.signal = zd_rx_qual_percent(buffer, + stats.signal = status->signal_strength; + stats.qual = zd_rx_qual_percent(buffer, length - sizeof(struct rx_status), status); @@ -997,10 +997,10 @@ struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf) hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &mac->band; hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | - IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE; - hw->max_rssi = 100; - hw->max_signal = 100; + IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | + IEEE80211_HW_SIGNAL_DB; + hw->max_signal = 100; hw->queues = 1; hw->extra_tx_headroom = sizeof(struct zd_ctrlset); diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 75a34609eed7..909956c97c44 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -336,13 +336,16 @@ enum mac80211_rx_flags { * The low-level driver should provide this information (the subset * supported by hardware) to the 802.11 code with each received * frame. + * * @mactime: value in microseconds of the 64-bit Time Synchronization Function * (TSF) timer when the first data symbol (MPDU) arrived at the hardware. * @band: the active band when this frame was received * @freq: frequency the radio was tuned to when receiving this frame, in MHz - * @ssi: signal strength when receiving this frame - * @signal: used as 'qual' in statistics reporting - * @noise: PHY noise when receiving this frame + * @signal: signal strength when receiving this frame, either in dBm, in dB or + * unspecified depending on the hardware capabilities flags + * @IEEE80211_HW_SIGNAL_* + * @noise: noise when receiving this frame, in dBm. + * @qual: overall signal quality indication, in percent (0-100). * @antenna: antenna used * @rate_idx: index of data rate into band's supported rates * @flag: %RX_FLAG_* @@ -351,9 +354,9 @@ struct ieee80211_rx_status { u64 mactime; enum ieee80211_band band; int freq; - int ssi; int signal; int noise; + int qual; int antenna; int rate_idx; int flag; @@ -392,7 +395,8 @@ enum ieee80211_tx_status_flags { * relevant only if IEEE80211_TX_STATUS_AMPDU was set. * @ampdu_ack_map: block ack bit map for the aggregation. * relevant only if IEEE80211_TX_STATUS_AMPDU was set. - * @ack_signal: signal strength of the ACK frame + * @ack_signal: signal strength of the ACK frame either in dBm, dB or unspec + * depending on hardware capabilites flags @IEEE80211_HW_SIGNAL_* */ struct ieee80211_tx_status { struct ieee80211_tx_control control; @@ -703,6 +707,25 @@ enum ieee80211_tkip_key_type { * @IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE: * Hardware is not capable of receiving frames with short preamble on * the 2.4 GHz band. + * + * @IEEE80211_HW_SIGNAL_UNSPEC: + * Hardware can provide signal values but we don't know its units. We + * expect values between 0 and @max_signal. + * If possible please provide dB or dBm instead. + * + * @IEEE80211_HW_SIGNAL_DB: + * Hardware gives signal values in dB, decibel difference from an + * arbitrary, fixed reference. We expect values between 0 and @max_signal. + * If possible please provide dBm instead. + * + * @IEEE80211_HW_SIGNAL_DBM: + * Hardware gives signal values in dBm, decibel difference from + * one milliwatt. This is the preferred method since it is standardized + * between different devices. @max_signal does not need to be set. + * + * @IEEE80211_HW_NOISE_DBM: + * Hardware can provide noise (radio interference) values in units dBm, + * decibel difference from one milliwatt. */ enum ieee80211_hw_flags { IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE = 1<<0, @@ -710,6 +733,10 @@ enum ieee80211_hw_flags { IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING = 1<<2, IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE = 1<<3, IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE = 1<<4, + IEEE80211_HW_SIGNAL_UNSPEC = 1<<5, + IEEE80211_HW_SIGNAL_DB = 1<<6, + IEEE80211_HW_SIGNAL_DBM = 1<<7, + IEEE80211_HW_NOISE_DBM = 1<<8, }; /** @@ -740,12 +767,8 @@ enum ieee80211_hw_flags { * * @channel_change_time: time (in microseconds) it takes to change channels. * - * @max_rssi: Maximum value for ssi in RX information, use - * negative numbers for dBm and 0 to indicate no support. - * - * @max_signal: like @max_rssi, but for the signal value. - * - * @max_noise: like @max_rssi, but for the noise value. + * @max_signal: Maximum value for signal (rssi) in RX information, used + * only when @IEEE80211_HW_SIGNAL_UNSPEC or @IEEE80211_HW_SIGNAL_DB * * @queues: number of available hardware transmit queues for * data packets. WMM/QoS requires at least four, these @@ -775,9 +798,7 @@ struct ieee80211_hw { int channel_change_time; int vif_data_size; u16 queues, ampdu_queues; - s8 max_rssi; s8 max_signal; - s8 max_noise; }; /** diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c index 200ee1e63728..69dbc342a464 100644 --- a/net/ieee80211/ieee80211_rx.c +++ b/net/ieee80211/ieee80211_rx.c @@ -391,7 +391,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, wstats.updated = 0; if (rx_stats->mask & IEEE80211_STATMASK_RSSI) { - wstats.level = rx_stats->rssi; + wstats.level = rx_stats->signal; wstats.updated |= IW_QUAL_LEVEL_UPDATED; } else wstats.updated |= IW_QUAL_LEVEL_INVALID; diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 1f00273d99c2..a2cc0284c9d0 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -63,8 +63,8 @@ STA_FILE(tx_fragments, tx_fragments, LU); STA_FILE(tx_filtered, tx_filtered_count, LU); STA_FILE(tx_retry_failed, tx_retry_failed, LU); STA_FILE(tx_retry_count, tx_retry_count, LU); -STA_FILE(last_rssi, last_rssi, D); STA_FILE(last_signal, last_signal, D); +STA_FILE(last_qual, last_qual, D); STA_FILE(last_noise, last_noise, D); STA_FILE(channel_use, channel_use, D); STA_FILE(wep_weak_iv_count, wep_weak_iv_count, LU); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 173b7fcb3029..ed0d9b35ae6f 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -82,7 +82,7 @@ struct ieee80211_sta_bss { u16 capability; /* host byte order */ enum ieee80211_band band; int freq; - int rssi, signal, noise; + int signal, noise, qual; u8 *wpa_ie; size_t wpa_ie_len; u8 *rsn_ie; diff --git a/net/mac80211/main.c b/net/mac80211/main.c index f277407f0f5a..390df48dfd40 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -1702,13 +1702,13 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) local->hw.conf.beacon_int = 1000; - local->wstats_flags |= local->hw.max_rssi ? - IW_QUAL_LEVEL_UPDATED : IW_QUAL_LEVEL_INVALID; - local->wstats_flags |= local->hw.max_signal ? + local->wstats_flags |= local->hw.flags & (IEEE80211_HW_SIGNAL_UNSPEC | + IEEE80211_HW_SIGNAL_DB | + IEEE80211_HW_SIGNAL_DBM) ? IW_QUAL_QUAL_UPDATED : IW_QUAL_QUAL_INVALID; - local->wstats_flags |= local->hw.max_noise ? + local->wstats_flags |= local->hw.flags & IEEE80211_HW_NOISE_DBM ? IW_QUAL_NOISE_UPDATED : IW_QUAL_NOISE_INVALID; - if (local->hw.max_rssi < 0 || local->hw.max_noise < 0) + if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) local->wstats_flags |= IW_QUAL_DBM; result = sta_info_start(local); diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 6c4b27be35da..dda30e98aa1e 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1959,8 +1959,8 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, local->hw.conf.channel->center_freq, ifsta->ssid, ifsta->ssid_len); if (bss) { - sta->last_rssi = bss->rssi; sta->last_signal = bss->signal; + sta->last_qual = bss->qual; sta->last_noise = bss->noise; ieee80211_rx_bss_put(dev, bss); } @@ -2629,9 +2629,9 @@ static void ieee80211_rx_bss_info(struct net_device *dev, bss->timestamp = beacon_timestamp; bss->last_update = jiffies; - bss->rssi = rx_status->ssi; bss->signal = rx_status->signal; bss->noise = rx_status->noise; + bss->qual = rx_status->qual; if (!beacon && !bss->probe_resp) bss->probe_resp = true; @@ -3427,9 +3427,9 @@ static int ieee80211_sta_config_auth(struct net_device *dev, !ieee80211_sta_match_ssid(ifsta, bss->ssid, bss->ssid_len)) continue; - if (!selected || top_rssi < bss->rssi) { + if (!selected || top_rssi < bss->signal) { selected = bss; - top_rssi = bss->rssi; + top_rssi = bss->signal; } } if (selected) @@ -4060,8 +4060,8 @@ ieee80211_sta_scan_result(struct net_device *dev, memset(&iwe, 0, sizeof(iwe)); iwe.cmd = IWEVQUAL; - iwe.u.qual.qual = bss->signal; - iwe.u.qual.level = bss->rssi; + iwe.u.qual.qual = bss->qual; + iwe.u.qual.level = bss->signal; iwe.u.qual.noise = bss->noise; iwe.u.qual.updated = local->wstats_flags; current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index b399e09ec7aa..474f13662c84 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -209,7 +209,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, cpu_to_le16(IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ); - rtfixed->antsignal = status->ssi; + rtfixed->antsignal = status->signal; rthdr->it_len = cpu_to_le16(rtap_len); } @@ -719,8 +719,8 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) sta->rx_fragments++; sta->rx_bytes += rx->skb->len; - sta->last_rssi = rx->status->ssi; sta->last_signal = rx->status->signal; + sta->last_qual = rx->status->qual; sta->last_noise = rx->status->noise; if (!(rx->fc & IEEE80211_FCTL_MOREFRAGS)) { diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 97a61c39ad90..e89cc1655547 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -216,8 +216,8 @@ struct sta_info { * from this STA */ unsigned long rx_fragments; /* number of received MPDUs */ unsigned long rx_dropped; /* number of dropped MPDUs from this STA */ - int last_rssi; /* RSSI of last received frame from this STA */ int last_signal; /* signal of last received frame from this STA */ + int last_qual; /* qual of last received frame from this STA */ int last_noise; /* noise of last received frame from this STA */ /* last received seq/frag number from this STA (per RX queue) */ __le16 last_seq_ctrl[NUM_RX_DATA_QUEUES]; diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c index 76e1de1dc735..6a342a9a40cd 100644 --- a/net/mac80211/wext.c +++ b/net/mac80211/wext.c @@ -169,14 +169,26 @@ static int ieee80211_ioctl_giwrange(struct net_device *dev, range->num_encoding_sizes = 2; range->max_encoding_tokens = NUM_DEFAULT_KEYS; - range->max_qual.qual = local->hw.max_signal; - range->max_qual.level = local->hw.max_rssi; - range->max_qual.noise = local->hw.max_noise; + if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC || + local->hw.flags & IEEE80211_HW_SIGNAL_DB) + range->max_qual.level = local->hw.max_signal; + else if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) + range->max_qual.level = -110; + else + range->max_qual.level = 0; + + if (local->hw.flags & IEEE80211_HW_NOISE_DBM) + range->max_qual.noise = -110; + else + range->max_qual.noise = 0; + + range->max_qual.qual = 100; range->max_qual.updated = local->wstats_flags; - range->avg_qual.qual = local->hw.max_signal/2; - range->avg_qual.level = 0; - range->avg_qual.noise = 0; + range->avg_qual.qual = 50; + /* not always true but better than nothing */ + range->avg_qual.level = range->max_qual.level / 2; + range->avg_qual.noise = range->max_qual.noise / 2; range->avg_qual.updated = local->wstats_flags; range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | @@ -996,8 +1008,8 @@ static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev wstats->qual.noise = 0; wstats->qual.updated = IW_QUAL_ALL_INVALID; } else { - wstats->qual.level = sta->last_rssi; - wstats->qual.qual = sta->last_signal; + wstats->qual.level = sta->last_signal; + wstats->qual.qual = sta->last_qual; wstats->qual.noise = sta->last_noise; wstats->qual.updated = local->wstats_flags; } -- cgit v1.2.3