From cd87a2d3a33d75a646f1aa1aa2ee5bf712d6f963 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 24 Sep 2010 11:20:47 +0200 Subject: mac80211: fix use-after-free commit 8c0c709eea5cbab97fb464cd68b06f24acc58ee1 Author: Johannes Berg Date: Wed Nov 25 17:46:15 2009 +0100 mac80211: move cmntr flag out of rx flags moved the CMTR flag into the skb's status, and in doing so introduced a use-after-free -- when the skb has been handed to cooked monitors the status setting will touch now invalid memory. Additionally, moving it there has effectively discarded the optimisation -- since the bit is only ever set on freed SKBs, and those were a copy, it could never be checked. For the current release, fixing this properly is a bit too involved, so let's just remove the problematic code and leave userspace with one copy of each frame for each virtual interface. Cc: stable@kernel.org [2.6.33+] Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/rx.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index fa0f37e4afe4..28624282c5f3 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2199,9 +2199,6 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx, struct net_device *prev_dev = NULL; struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); - if (status->flag & RX_FLAG_INTERNAL_CMTR) - goto out_free_skb; - if (skb_headroom(skb) < sizeof(*rthdr) && pskb_expand_head(skb, sizeof(*rthdr), 0, GFP_ATOMIC)) goto out_free_skb; @@ -2260,7 +2257,6 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx, } else goto out_free_skb; - status->flag |= RX_FLAG_INTERNAL_CMTR; return; out_free_skb: -- cgit v1.2.3 From 8dcb20038ade81f9a87c024e7f12ec74f0e95f33 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sat, 28 Aug 2010 19:36:10 +0300 Subject: mac80211: Filter ProbeReq SuppRates based on TX rate mask If the TX rate set has been masked, the removed rates can also be removed from the Supported Rates and Extended Supported Rates IEs in Probe Request frames. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville --- net/mac80211/ieee80211_i.h | 2 +- net/mac80211/scan.c | 2 +- net/mac80211/util.c | 37 ++++++++++++++++++++++--------------- 3 files changed, 24 insertions(+), 17 deletions(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 9346a6b0f400..3641563d90f8 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1256,7 +1256,7 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, const u8 *key, u8 key_len, u8 key_idx); int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, const u8 *ie, size_t ie_len, - enum ieee80211_band band); + enum ieee80211_band band, u32 rate_mask); void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, const u8 *ssid, size_t ssid_len, const u8 *ie, size_t ie_len); diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index d60389ba9b95..1623e9d2086e 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -242,7 +242,7 @@ static bool ieee80211_prep_hw_scan(struct ieee80211_local *local) local->hw_scan_req->n_channels = n_chans; ielen = ieee80211_build_preq_ies(local, (u8 *)local->hw_scan_req->ie, - req->ie, req->ie_len, band); + req->ie, req->ie_len, band, (u32) -1); local->hw_scan_req->ie_len = ielen; return true; diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 737f4267c335..bfd19d76667a 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -895,26 +895,33 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, const u8 *ie, size_t ie_len, - enum ieee80211_band band) + enum ieee80211_band band, u32 rate_mask) { struct ieee80211_supported_band *sband; u8 *pos; size_t offset = 0, noffset; int supp_rates_len, i; + u8 rates[32]; + int num_rates; + int ext_rates_len; sband = local->hw.wiphy->bands[band]; pos = buffer; - supp_rates_len = min_t(int, sband->n_bitrates, 8); + num_rates = 0; + for (i = 0; i < sband->n_bitrates; i++) { + if ((BIT(i) & rate_mask) == 0) + continue; /* skip rate */ + rates[num_rates++] = (u8) (sband->bitrates[i].bitrate / 5); + } + + supp_rates_len = min_t(int, num_rates, 8); *pos++ = WLAN_EID_SUPP_RATES; *pos++ = supp_rates_len; - - for (i = 0; i < supp_rates_len; i++) { - int rate = sband->bitrates[i].bitrate; - *pos++ = (u8) (rate / 5); - } + memcpy(pos, rates, supp_rates_len); + pos += supp_rates_len; /* insert "request information" if in custom IEs */ if (ie && ie_len) { @@ -932,14 +939,12 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, offset = noffset; } - if (sband->n_bitrates > i) { + ext_rates_len = num_rates - supp_rates_len; + if (ext_rates_len > 0) { *pos++ = WLAN_EID_EXT_SUPP_RATES; - *pos++ = sband->n_bitrates - i; - - for (; i < sband->n_bitrates; i++) { - int rate = sband->bitrates[i].bitrate; - *pos++ = (u8) (rate / 5); - } + *pos++ = ext_rates_len; + memcpy(pos, rates + supp_rates_len, ext_rates_len); + pos += ext_rates_len; } /* insert custom IEs that go before HT */ @@ -1018,7 +1023,9 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, } buf_len = ieee80211_build_preq_ies(local, buf, ie, ie_len, - local->hw.conf.channel->band); + local->hw.conf.channel->band, + sdata->rc_rateidx_mask + [local->hw.conf.channel->band]); skb = ieee80211_probereq_get(&local->hw, &sdata->vif, ssid, ssid_len, -- cgit v1.2.3 From 651b52254fc061f02d965524e71de4333a009a5a Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sat, 28 Aug 2010 19:37:51 +0300 Subject: mac80211: Add DS Parameter Set into Probe Request on 2.4 GHz IEEE Std 802.11k-2008 added DS Parameter Set information element into Probe Request frames as an optional information on 2.4 GHz band (and mandatory, if radio measurements are enabled). This allows APs to filter out Probe Request frames that may be received from neighboring overlapping channels and by doing so, reduce the number of unnecessary frames in the air. Make mac80211 add this IE into Probe Request frames whenever the channel is known (i.e., whenever hwscan is not used). Signed-off-by: Jouni Malinen Acked-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211_i.h | 3 ++- net/mac80211/scan.c | 3 ++- net/mac80211/util.c | 16 ++++++++++++++-- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 3641563d90f8..78a8d9208cec 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1256,7 +1256,8 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, const u8 *key, u8 key_len, u8 key_idx); int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, const u8 *ie, size_t ie_len, - enum ieee80211_band band, u32 rate_mask); + enum ieee80211_band band, u32 rate_mask, + u8 channel); void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, const u8 *ssid, size_t ssid_len, const u8 *ie, size_t ie_len); diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 1623e9d2086e..5171a9581631 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -242,7 +242,8 @@ static bool ieee80211_prep_hw_scan(struct ieee80211_local *local) local->hw_scan_req->n_channels = n_chans; ielen = ieee80211_build_preq_ies(local, (u8 *)local->hw_scan_req->ie, - req->ie, req->ie_len, band, (u32) -1); + req->ie, req->ie_len, band, (u32) -1, + 0); local->hw_scan_req->ie_len = ielen; return true; diff --git a/net/mac80211/util.c b/net/mac80211/util.c index bfd19d76667a..aba025d748e9 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -895,7 +895,8 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, const u8 *ie, size_t ie_len, - enum ieee80211_band band, u32 rate_mask) + enum ieee80211_band band, u32 rate_mask, + u8 channel) { struct ieee80211_supported_band *sband; u8 *pos; @@ -947,6 +948,12 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, pos += ext_rates_len; } + if (channel && sband->band == IEEE80211_BAND_2GHZ) { + *pos++ = WLAN_EID_DS_PARAMS; + *pos++ = 1; + *pos++ = channel; + } + /* insert custom IEs that go before HT */ if (ie && ie_len) { static const u8 before_ht[] = { @@ -1013,6 +1020,7 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, struct ieee80211_mgmt *mgmt; size_t buf_len; u8 *buf; + u8 chan; /* FIXME: come up with a proper value */ buf = kmalloc(200 + ie_len, GFP_KERNEL); @@ -1022,10 +1030,14 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, return; } + chan = ieee80211_frequency_to_channel( + local->hw.conf.channel->center_freq); + buf_len = ieee80211_build_preq_ies(local, buf, ie, ie_len, local->hw.conf.channel->band, sdata->rc_rateidx_mask - [local->hw.conf.channel->band]); + [local->hw.conf.channel->band], + chan); skb = ieee80211_probereq_get(&local->hw, &sdata->vif, ssid, ssid_len, -- cgit v1.2.3 From ed627be38a1a07c6986a9f17c299f6afc86ac6b7 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sun, 12 Sep 2010 01:48:33 +0200 Subject: airo: remove "basic_rate" module option The "basic_rate" module option is not implemented correctly. If the rate was set to zero it was supposed to set it to "basic_rate | 0x80". Unfortunately the check to see if what zero was wrong and it checked "!ai->config.rates" (which is always false) instead of "!ai->config.rates[i]". This option was just used for development and it wasn't documented anywhere. Instead of fixing it, we can just remove it. Reported-by: Stanislaw Gruszka Signed-off-by: Dan Carpenter Signed-off-by: John W. Linville --- drivers/net/wireless/airo.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index c7528e5794d1..fdebbe7eebb6 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -217,7 +217,6 @@ static const char *statsLabels[] = { (no spaces) list of rates (up to 8). */ static int rates[8]; -static int basic_rate; static char *ssids[3]; static int io[4]; @@ -250,7 +249,6 @@ MODULE_LICENSE("Dual BSD/GPL"); MODULE_SUPPORTED_DEVICE("Aironet 4500, 4800 and Cisco 340/350"); module_param_array(io, int, NULL, 0); module_param_array(irq, int, NULL, 0); -module_param(basic_rate, int, 0); module_param_array(rates, int, NULL, 0); module_param_array(ssids, charp, NULL, 0); module_param(auto_wep, int, 0); @@ -3884,15 +3882,6 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock) ai->config.rates[i] = rates[i]; } } - if ( basic_rate > 0 ) { - for( i = 0; i < 8; i++ ) { - if ( ai->config.rates[i] == basic_rate || - !ai->config.rates ) { - ai->config.rates[i] = basic_rate | 0x80; - break; - } - } - } set_bit (FLAG_COMMIT, &ai->flags); } -- cgit v1.2.3 From eb7d3066cf864342e8ae6a5c1126a1602c4d06c0 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Tue, 21 Sep 2010 21:36:18 +0200 Subject: mac80211: clear txflags for ps-filtered frames This patch fixes stale mac80211_tx_control_flags for filtered / retried frames. Because ieee80211_handle_filtered_frame feeds skbs back into the tx path, they have to be stripped of some tx flags so they won't confuse the stack, driver or device. Cc: Acked-by: Johannes Berg Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- include/net/mac80211.h | 16 ++++++++++++++++ net/mac80211/status.c | 1 + 2 files changed, 17 insertions(+) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 12a49f0ba32c..5d1187d7c5e5 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -321,6 +321,9 @@ struct ieee80211_bss_conf { * @IEEE80211_TX_CTL_LDPC: tells the driver to use LDPC for this frame * @IEEE80211_TX_CTL_STBC: Enables Space-Time Block Coding (STBC) for this * frame and selects the maximum number of streams that it can use. + * + * Note: If you have to add new flags to the enumeration, then don't + * forget to update %IEEE80211_TX_TEMPORARY_FLAGS when necessary. */ enum mac80211_tx_control_flags { IEEE80211_TX_CTL_REQ_TX_STATUS = BIT(0), @@ -350,6 +353,19 @@ enum mac80211_tx_control_flags { #define IEEE80211_TX_CTL_STBC_SHIFT 23 +/* + * This definition is used as a mask to clear all temporary flags, which are + * set by the tx handlers for each transmission attempt by the mac80211 stack. + */ +#define IEEE80211_TX_TEMPORARY_FLAGS (IEEE80211_TX_CTL_NO_ACK | \ + IEEE80211_TX_CTL_CLEAR_PS_FILT | IEEE80211_TX_CTL_FIRST_FRAGMENT | \ + IEEE80211_TX_CTL_SEND_AFTER_DTIM | IEEE80211_TX_CTL_AMPDU | \ + IEEE80211_TX_STAT_TX_FILTERED | IEEE80211_TX_STAT_ACK | \ + IEEE80211_TX_STAT_AMPDU | IEEE80211_TX_STAT_AMPDU_NO_BACK | \ + IEEE80211_TX_CTL_RATE_CTRL_PROBE | IEEE80211_TX_CTL_PSPOLL_RESPONSE | \ + IEEE80211_TX_CTL_MORE_FRAMES | IEEE80211_TX_CTL_LDPC | \ + IEEE80211_TX_CTL_STBC) + /** * enum mac80211_rate_control_flags - per-rate flags set by the * Rate Control algorithm. diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 571b32bfc54c..dd85006c4fe8 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -58,6 +58,7 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, info->control.vif = &sta->sdata->vif; info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING | IEEE80211_TX_INTFL_RETRANSMISSION; + info->flags &= ~IEEE80211_TX_TEMPORARY_FLAGS; sta->tx_filtered_count++; -- cgit v1.2.3 From 9094537c3a9ef9e127e844254a74186735c9a90b Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Mon, 20 Sep 2010 22:54:46 -0700 Subject: ath9k: Fix tx struck state with paprd Paprd needs to be done only on active chains(not for all the chains that hw can support). The paprd training frames which are sent for inactive chains would be hanging on the hw queue without getting transmitted and would make the connection so unstable. This issue happens only with the hw which supports paprd cal(ar9003). Signed-off-by: Vasanthakumar Thiagarajan Cc: stable@kernel.org Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 8b327bcad695..a13387882636 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -270,6 +270,7 @@ static void ath_paprd_activate(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; struct ath9k_hw_cal_data *caldata = ah->caldata; + struct ath_common *common = ath9k_hw_common(ah); int chain; if (!caldata || !caldata->paprd_done) @@ -278,7 +279,7 @@ static void ath_paprd_activate(struct ath_softc *sc) ath9k_ps_wakeup(sc); ar9003_paprd_enable(ah, false); for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) { - if (!(ah->caps.tx_chainmask & BIT(chain))) + if (!(common->tx_chainmask & BIT(chain))) continue; ar9003_paprd_populate_single_table(ah, caldata, chain); @@ -300,6 +301,7 @@ void ath_paprd_calibrate(struct work_struct *work) struct ieee80211_supported_band *sband = &sc->sbands[band]; struct ath_tx_control txctl; struct ath9k_hw_cal_data *caldata = ah->caldata; + struct ath_common *common = ath9k_hw_common(ah); int qnum, ftype; int chain_ok = 0; int chain; @@ -333,7 +335,7 @@ void ath_paprd_calibrate(struct work_struct *work) ath9k_ps_wakeup(sc); ar9003_paprd_init_table(ah); for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) { - if (!(ah->caps.tx_chainmask & BIT(chain))) + if (!(common->tx_chainmask & BIT(chain))) continue; chain_ok = 0; -- cgit v1.2.3 From 9cf13668a5f8165a81349defc5f82c57a4a8279b Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Tue, 21 Sep 2010 12:58:09 +0530 Subject: ath9k_htc: Fix beacon distribution in IBSS mode This patch ensures fair beacon distribution in IBSS mode by configuring proper CWmin based on slot time. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/htc_drv_beacon.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index bd1506e69105..1b72aa482ac7 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -235,7 +235,14 @@ void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv) ath9k_hw_get_txq_props(ah, qnum, &qi_be); qi.tqi_aifs = qi_be.tqi_aifs; - qi.tqi_cwmin = 4*qi_be.tqi_cwmin; + /* For WIFI Beacon Distribution + * Long slot time : 2x cwmin + * Short slot time : 4x cwmin + */ + if (ah->slottime == ATH9K_SLOT_TIME_20) + qi.tqi_cwmin = 2*qi_be.tqi_cwmin; + else + qi.tqi_cwmin = 4*qi_be.tqi_cwmin; qi.tqi_cwmax = qi_be.tqi_cwmax; if (!ath9k_hw_set_txq_props(ah, priv->beaconq, &qi)) { -- cgit v1.2.3 From 87fd2e6c90acb45a5741207fc953190596f93841 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Tue, 21 Sep 2010 17:03:57 -0700 Subject: ath5k: Add bssid mask and rxfilter to debugfs. Helps with debugging virtual interfaces. Signed-off-by: Ben Greear Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/debug.c | 58 ++++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath5k/debug.h | 1 + 2 files changed, 59 insertions(+) diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c index 6583a82a0783..0f06e8490314 100644 --- a/drivers/net/wireless/ath/ath5k/debug.c +++ b/drivers/net/wireless/ath/ath5k/debug.c @@ -483,6 +483,59 @@ static const struct file_operations fops_antenna = { .owner = THIS_MODULE, }; +/* debugfs: misc */ + +static ssize_t read_file_misc(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath5k_softc *sc = file->private_data; + char buf[700]; + unsigned int len = 0; + u32 filt = ath5k_hw_get_rx_filter(sc->ah); + + len += snprintf(buf+len, sizeof(buf)-len, "bssid-mask: %pM\n", + sc->bssidmask); + len += snprintf(buf+len, sizeof(buf)-len, "filter-flags: 0x%x ", + filt); + if (filt & AR5K_RX_FILTER_UCAST) + len += snprintf(buf+len, sizeof(buf)-len, " UCAST"); + if (filt & AR5K_RX_FILTER_MCAST) + len += snprintf(buf+len, sizeof(buf)-len, " MCAST"); + if (filt & AR5K_RX_FILTER_BCAST) + len += snprintf(buf+len, sizeof(buf)-len, " BCAST"); + if (filt & AR5K_RX_FILTER_CONTROL) + len += snprintf(buf+len, sizeof(buf)-len, " CONTROL"); + if (filt & AR5K_RX_FILTER_BEACON) + len += snprintf(buf+len, sizeof(buf)-len, " BEACON"); + if (filt & AR5K_RX_FILTER_PROM) + len += snprintf(buf+len, sizeof(buf)-len, " PROM"); + if (filt & AR5K_RX_FILTER_XRPOLL) + len += snprintf(buf+len, sizeof(buf)-len, " XRPOLL"); + if (filt & AR5K_RX_FILTER_PROBEREQ) + len += snprintf(buf+len, sizeof(buf)-len, " PROBEREQ"); + if (filt & AR5K_RX_FILTER_PHYERR_5212) + len += snprintf(buf+len, sizeof(buf)-len, " PHYERR-5212"); + if (filt & AR5K_RX_FILTER_RADARERR_5212) + len += snprintf(buf+len, sizeof(buf)-len, " RADARERR-5212"); + if (filt & AR5K_RX_FILTER_PHYERR_5211) + snprintf(buf+len, sizeof(buf)-len, " PHYERR-5211"); + if (filt & AR5K_RX_FILTER_RADARERR_5211) + len += snprintf(buf+len, sizeof(buf)-len, " RADARERR-5211\n"); + else + len += snprintf(buf+len, sizeof(buf)-len, "\n"); + + if (len > sizeof(buf)) + len = sizeof(buf); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static const struct file_operations fops_misc = { + .read = read_file_misc, + .open = ath5k_debugfs_open, + .owner = THIS_MODULE, +}; + /* debugfs: frameerrors */ @@ -856,6 +909,10 @@ ath5k_debug_init_device(struct ath5k_softc *sc) S_IWUSR | S_IRUSR, sc->debug.debugfs_phydir, sc, &fops_antenna); + sc->debug.debugfs_misc = debugfs_create_file("misc", + S_IRUSR, + sc->debug.debugfs_phydir, sc, &fops_misc); + sc->debug.debugfs_frameerrors = debugfs_create_file("frameerrors", S_IWUSR | S_IRUSR, sc->debug.debugfs_phydir, sc, @@ -886,6 +943,7 @@ ath5k_debug_finish_device(struct ath5k_softc *sc) debugfs_remove(sc->debug.debugfs_beacon); debugfs_remove(sc->debug.debugfs_reset); debugfs_remove(sc->debug.debugfs_antenna); + debugfs_remove(sc->debug.debugfs_misc); debugfs_remove(sc->debug.debugfs_frameerrors); debugfs_remove(sc->debug.debugfs_ani); debugfs_remove(sc->debug.debugfs_queue); diff --git a/drivers/net/wireless/ath/ath5k/debug.h b/drivers/net/wireless/ath/ath5k/debug.h index 9b22722a95f0..4f078b134015 100644 --- a/drivers/net/wireless/ath/ath5k/debug.h +++ b/drivers/net/wireless/ath/ath5k/debug.h @@ -75,6 +75,7 @@ struct ath5k_dbg_info { struct dentry *debugfs_beacon; struct dentry *debugfs_reset; struct dentry *debugfs_antenna; + struct dentry *debugfs_misc; struct dentry *debugfs_frameerrors; struct dentry *debugfs_ani; struct dentry *debugfs_queue; -- cgit v1.2.3 From 67e0208acea29682f5766eb9f67f6f26117eef3e Mon Sep 17 00:00:00 2001 From: Ido Yariv Date: Wed, 22 Sep 2010 09:53:13 +0200 Subject: wl1271: Fix overflow in wl1271_boot_upload_nvs Due to miscalculation of nvs_len, excessive data was sent to the firmware. Fix this by first setting nvs_ptr to point to the first NVS table, and computing the total size of all NVS tables accordingly. Signed-off-by: Ido Yariv Tested-By: Tuomas Katila Acked-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_boot.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/wl12xx/wl1271_boot.c b/drivers/net/wireless/wl12xx/wl1271_boot.c index fc21db810812..e5a7f042645f 100644 --- a/drivers/net/wireless/wl12xx/wl1271_boot.c +++ b/drivers/net/wireless/wl12xx/wl1271_boot.c @@ -274,11 +274,11 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) /* * We've reached the first zero length, the first NVS table - * is 7 bytes further. + * is located at an aligned offset which is at least 7 bytes further. */ - nvs_ptr += 7; + nvs_ptr = (u8 *)wl->nvs->nvs + + ALIGN(nvs_ptr - (u8 *)wl->nvs->nvs + 7, 4); nvs_len -= nvs_ptr - (u8 *)wl->nvs->nvs; - nvs_len = ALIGN(nvs_len, 4); /* FIXME: The driver sets the partition here, but this is not needed, since it sets to the same one as currently in use */ @@ -286,14 +286,9 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) wl1271_set_partition(wl, &part_table[PART_WORK]); /* Copy the NVS tables to a new block to ensure alignment */ - /* FIXME: We jump 3 more bytes before uploading the NVS. It seems - that our NVS files have three extra zeros here. I'm not sure whether - the problem is in our NVS generation or we should really jumpt these - 3 bytes here */ - nvs_ptr += 3; - - nvs_aligned = kmemdup(nvs_ptr, nvs_len, GFP_KERNEL); if - (!nvs_aligned) return -ENOMEM; + nvs_aligned = kmemdup(nvs_ptr, nvs_len, GFP_KERNEL); + if (!nvs_aligned) + return -ENOMEM; /* And finally we upload the NVS tables */ /* FIXME: In wl1271, we upload everything at once. -- cgit v1.2.3 From 7a37081e2e25e58701b17c41579fd06bc353b392 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 22 Sep 2010 12:34:52 +0200 Subject: ath9k_hw: simplify revision checks for AR9280 Since AR9280 v1.0 was never sold (and the initvals removed), v1.0 specific revision checks can be removed and the 'v2.0 or later' check can be simplified to a check for AR9280 or later. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar5008_phy.c | 14 +++++++------- drivers/net/wireless/ath/ath9k/ar9002_calib.c | 6 +++--- drivers/net/wireless/ath/ath9k/ar9002_hw.c | 2 +- drivers/net/wireless/ath/ath9k/eeprom_4k.c | 4 ++-- drivers/net/wireless/ath/ath9k/eeprom_9287.c | 6 +++--- drivers/net/wireless/ath/ath9k/eeprom_def.c | 18 +++++++++--------- drivers/net/wireless/ath/ath9k/hw.c | 15 +++++++-------- drivers/net/wireless/ath/ath9k/init.c | 2 +- drivers/net/wireless/ath/ath9k/recv.c | 2 +- drivers/net/wireless/ath/ath9k/reg.h | 9 ++------- 10 files changed, 36 insertions(+), 42 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c index 3d2c8679bc85..9318ae736982 100644 --- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c @@ -118,7 +118,7 @@ static void ar5008_hw_force_bias(struct ath_hw *ah, u16 synth_freq) if (!AR_SREV_5416(ah) || synth_freq >= 3000) return; - BUG_ON(AR_SREV_9280_10_OR_LATER(ah)); + BUG_ON(AR_SREV_9280_20_OR_LATER(ah)); if (synth_freq < 2412) new_bias = 0; @@ -454,7 +454,7 @@ static int ar5008_hw_rf_alloc_ext_banks(struct ath_hw *ah) struct ath_common *common = ath9k_hw_common(ah); - BUG_ON(AR_SREV_9280_10_OR_LATER(ah)); + BUG_ON(AR_SREV_9280_20_OR_LATER(ah)); ATH_ALLOC_BANK(ah->analogBank0Data, ah->iniBank0.ia_rows); ATH_ALLOC_BANK(ah->analogBank1Data, ah->iniBank1.ia_rows); @@ -484,7 +484,7 @@ static void ar5008_hw_rf_free_ext_banks(struct ath_hw *ah) bank = NULL; \ } while (0); - BUG_ON(AR_SREV_9280_10_OR_LATER(ah)); + BUG_ON(AR_SREV_9280_20_OR_LATER(ah)); ATH_FREE_BANK(ah->analogBank0Data); ATH_FREE_BANK(ah->analogBank1Data); @@ -525,7 +525,7 @@ static bool ar5008_hw_set_rf_regs(struct ath_hw *ah, * for single chip devices, that is AR9280 or anything * after that. */ - if (AR_SREV_9280_10_OR_LATER(ah)) + if (AR_SREV_9280_20_OR_LATER(ah)) return true; /* Setup rf parameters */ @@ -663,7 +663,7 @@ static void ar5008_hw_override_ini(struct ath_hw *ah, */ REG_SET_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); - if (AR_SREV_9280_10_OR_LATER(ah)) { + if (AR_SREV_9280_20_OR_LATER(ah)) { val = REG_READ(ah, AR_PCU_MISC_MODE2); if (!AR_SREV_9271(ah)) @@ -676,7 +676,7 @@ static void ar5008_hw_override_ini(struct ath_hw *ah, } if (!AR_SREV_5416_20_OR_LATER(ah) || - AR_SREV_9280_10_OR_LATER(ah)) + AR_SREV_9280_20_OR_LATER(ah)) return; /* * Disable BB clock gating @@ -900,7 +900,7 @@ static void ar5008_hw_set_rfmode(struct ath_hw *ah, struct ath9k_channel *chan) rfMode |= (IS_CHAN_B(chan) || IS_CHAN_G(chan)) ? AR_PHY_MODE_DYNAMIC : AR_PHY_MODE_OFDM; - if (!AR_SREV_9280_10_OR_LATER(ah)) + if (!AR_SREV_9280_20_OR_LATER(ah)) rfMode |= (IS_CHAN_5GHZ(chan)) ? AR_PHY_MODE_RF5GHZ : AR_PHY_MODE_RF2GHZ; diff --git a/drivers/net/wireless/ath/ath9k/ar9002_calib.c b/drivers/net/wireless/ath/ath9k/ar9002_calib.c index fe7418aefc4a..dc64afeeaa12 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_calib.c @@ -841,7 +841,7 @@ static bool ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan) if (!ar9285_hw_clc(ah, chan)) return false; } else { - if (AR_SREV_9280_10_OR_LATER(ah)) { + if (AR_SREV_9280_20_OR_LATER(ah)) { if (!AR_SREV_9287_10_OR_LATER(ah)) REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); @@ -864,7 +864,7 @@ static bool ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan) return false; } - if (AR_SREV_9280_10_OR_LATER(ah)) { + if (AR_SREV_9280_20_OR_LATER(ah)) { if (!AR_SREV_9287_10_OR_LATER(ah)) REG_SET_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); @@ -976,7 +976,7 @@ static void ar9002_hw_init_cal_settings(struct ath_hw *ah) } if (AR_SREV_9160_10_OR_LATER(ah)) { - if (AR_SREV_9280_10_OR_LATER(ah)) { + if (AR_SREV_9280_20_OR_LATER(ah)) { ah->iq_caldata.calData = &iq_cal_single_sample; ah->adcgain_caldata.calData = &adc_gain_cal_single_sample; diff --git a/drivers/net/wireless/ath/ath9k/ar9002_hw.c b/drivers/net/wireless/ath/ath9k/ar9002_hw.c index 94392daebaa0..fde45082a13b 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_hw.c @@ -569,7 +569,7 @@ void ar9002_hw_attach_ops(struct ath_hw *ah) ops->config_pci_powersave = ar9002_hw_configpcipowersave; ar5008_hw_attach_phy_ops(ah); - if (AR_SREV_9280_10_OR_LATER(ah)) + if (AR_SREV_9280_20_OR_LATER(ah)) ar9002_hw_attach_phy_ops(ah); ar9002_hw_attach_calib_ops(ah); diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c index ead8b0dd3b53..677e0c9d0481 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c @@ -333,7 +333,7 @@ static void ath9k_hw_get_4k_gain_boundaries_pdadcs(struct ath_hw *ah, } if (i == 0) { - if (AR_SREV_9280_10_OR_LATER(ah)) + if (AR_SREV_9280_20_OR_LATER(ah)) ss = (int16_t)(0 - (minPwrT4[i] / 2)); else ss = 0; @@ -761,7 +761,7 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah, regulatory->max_power_level = ratesArray[i]; - if (AR_SREV_9280_10_OR_LATER(ah)) { + if (AR_SREV_9280_20_OR_LATER(ah)) { for (i = 0; i < Ar5416RateSize; i++) ratesArray[i] -= AR5416_PWR_TABLE_OFFSET_DB * 2; } diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c index e6186515d05b..966b9496a9dd 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c @@ -324,7 +324,7 @@ static void ath9k_hw_get_ar9287_gain_boundaries_pdadcs(struct ath_hw *ah, minDelta = 0; if (i == 0) { - if (AR_SREV_9280_10_OR_LATER(ah)) + if (AR_SREV_9280_20_OR_LATER(ah)) ss = (int16_t)(0 - (minPwrT4[i] / 2)); else ss = 0; @@ -883,7 +883,7 @@ static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah, ratesArray[i] = AR9287_MAX_RATE_POWER; } - if (AR_SREV_9280_10_OR_LATER(ah)) { + if (AR_SREV_9280_20_OR_LATER(ah)) { for (i = 0; i < Ar5416RateSize; i++) ratesArray[i] -= AR9287_PWR_TABLE_OFFSET_DB * 2; } @@ -977,7 +977,7 @@ static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah, else i = rate6mb; - if (AR_SREV_9280_10_OR_LATER(ah)) + if (AR_SREV_9280_20_OR_LATER(ah)) regulatory->max_power_level = ratesArray[i] + AR9287_PWR_TABLE_OFFSET_DB * 2; else diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c index 23f480d4c770..76b4d65472dd 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_def.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c @@ -223,7 +223,7 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah) } /* Enable fixup for AR_AN_TOP2 if necessary */ - if (AR_SREV_9280_10_OR_LATER(ah) && + if (AR_SREV_9280_20_OR_LATER(ah) && (eep->baseEepHeader.version & 0xff) > 0x0a && eep->baseEepHeader.pwdclkind == 0) ah->need_an_top2_fixup = 1; @@ -317,7 +317,7 @@ static void ath9k_hw_def_set_gain(struct ath_hw *ah, if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_3) { txRxAttenLocal = pModal->txRxAttenCh[i]; - if (AR_SREV_9280_10_OR_LATER(ah)) { + if (AR_SREV_9280_20_OR_LATER(ah)) { REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, pModal->bswMargin[i]); @@ -344,7 +344,7 @@ static void ath9k_hw_def_set_gain(struct ath_hw *ah, } } - if (AR_SREV_9280_10_OR_LATER(ah)) { + if (AR_SREV_9280_20_OR_LATER(ah)) { REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal); @@ -408,7 +408,7 @@ static void ath9k_hw_def_set_board_values(struct ath_hw *ah, regChainOffset, i); } - if (AR_SREV_9280_10_OR_LATER(ah)) { + if (AR_SREV_9280_20_OR_LATER(ah)) { if (IS_CHAN_2GHZ(chan)) { ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH0, AR_AN_RF2G1_CH0_OB, @@ -461,7 +461,7 @@ static void ath9k_hw_def_set_board_values(struct ath_hw *ah, REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC, pModal->adcDesiredSize); - if (!AR_SREV_9280_10_OR_LATER(ah)) + if (!AR_SREV_9280_20_OR_LATER(ah)) REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_PGA, pModal->pgaDesiredSize); @@ -478,7 +478,7 @@ static void ath9k_hw_def_set_board_values(struct ath_hw *ah, REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON, pModal->txEndToRxOn); - if (AR_SREV_9280_10_OR_LATER(ah)) { + if (AR_SREV_9280_20_OR_LATER(ah)) { REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62, pModal->thresh62); REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, @@ -696,7 +696,7 @@ static void ath9k_hw_get_def_gain_boundaries_pdadcs(struct ath_hw *ah, } if (i == 0) { - if (AR_SREV_9280_10_OR_LATER(ah)) + if (AR_SREV_9280_20_OR_LATER(ah)) ss = (int16_t)(0 - (minPwrT4[i] / 2)); else ss = 0; @@ -1291,7 +1291,7 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah, ratesArray[i] = AR5416_MAX_RATE_POWER; } - if (AR_SREV_9280_10_OR_LATER(ah)) { + if (AR_SREV_9280_20_OR_LATER(ah)) { for (i = 0; i < Ar5416RateSize; i++) { int8_t pwr_table_offset; @@ -1395,7 +1395,7 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah, else if (IS_CHAN_HT20(chan)) i = rateHt20_0; - if (AR_SREV_9280_10_OR_LATER(ah)) + if (AR_SREV_9280_20_OR_LATER(ah)) regulatory->max_power_level = ratesArray[i] + AR5416_PWR_TABLE_OFFSET_DB * 2; else diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 0b2ff98b6f33..f2255a211637 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -565,7 +565,7 @@ static int __ath9k_hw_init(struct ath_hw *ah) ath9k_hw_init_cal_settings(ah); ah->ani_function = ATH9K_ANI_ALL; - if (AR_SREV_9280_10_OR_LATER(ah) && !AR_SREV_9300_20_OR_LATER(ah)) + if (AR_SREV_9280_20_OR_LATER(ah) && !AR_SREV_9300_20_OR_LATER(ah)) ah->ani_function &= ~ATH9K_ANI_NOISE_IMMUNITY_LEVEL; if (!AR_SREV_9300_20_OR_LATER(ah)) ah->ani_function &= ~ATH9K_ANI_MRC_CCK; @@ -1312,7 +1312,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, if (tsf) ath9k_hw_settsf64(ah, tsf); - if (AR_SREV_9280_10_OR_LATER(ah)) + if (AR_SREV_9280_20_OR_LATER(ah)) REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE); if (!AR_SREV_9300_20_OR_LATER(ah)) @@ -1857,8 +1857,7 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) /* Use rx_chainmask from EEPROM. */ pCap->rx_chainmask = ah->eep_ops->get_eeprom(ah, EEP_RX_MASK); - if (!(AR_SREV_9280(ah) && (ah->hw_version.macRev == 0))) - ah->misc_mode |= AR_PCU_MIC_NEW_LOC_ENA; + ah->misc_mode |= AR_PCU_MIC_NEW_LOC_ENA; pCap->low_2ghz_chan = 2312; pCap->high_2ghz_chan = 2732; @@ -1896,7 +1895,7 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) pCap->num_gpio_pins = AR7010_NUM_GPIO; else if (AR_SREV_9285_10_OR_LATER(ah)) pCap->num_gpio_pins = AR9285_NUM_GPIO; - else if (AR_SREV_9280_10_OR_LATER(ah)) + else if (AR_SREV_9280_20_OR_LATER(ah)) pCap->num_gpio_pins = AR928X_NUM_GPIO; else pCap->num_gpio_pins = AR_NUM_GPIO; @@ -1953,7 +1952,7 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) pCap->num_antcfg_2ghz = ah->eep_ops->get_num_ant_config(ah, ATH9K_HAL_FREQ_BAND_2GHZ); - if (AR_SREV_9280_10_OR_LATER(ah) && + if (AR_SREV_9280_20_OR_LATER(ah) && ath9k_hw_btcoex_supported(ah)) { btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO; btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO; @@ -2078,7 +2077,7 @@ u32 ath9k_hw_gpio_get(struct ath_hw *ah, u32 gpio) return MS_REG_READ(AR9287, gpio) != 0; else if (AR_SREV_9285_10_OR_LATER(ah)) return MS_REG_READ(AR9285, gpio) != 0; - else if (AR_SREV_9280_10_OR_LATER(ah)) + else if (AR_SREV_9280_20_OR_LATER(ah)) return MS_REG_READ(AR928X, gpio) != 0; else return MS_REG_READ(AR, gpio) != 0; @@ -2575,7 +2574,7 @@ void ath9k_hw_name(struct ath_hw *ah, char *hw_name, size_t len) int used; /* chipsets >= AR9280 are single-chip */ - if (AR_SREV_9280_10_OR_LATER(ah)) { + if (AR_SREV_9280_20_OR_LATER(ah)) { used = snprintf(hw_name, len, "Atheros AR%s Rev:%x", ath9k_hw_mac_bb_name(ah->hw_version.macVersion), diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 573899e27b3d..de3393867e37 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -211,7 +211,7 @@ static void setup_ht_cap(struct ath_softc *sc, else max_streams = 2; - if (AR_SREV_9280_10_OR_LATER(ah)) { + if (AR_SREV_9280_20_OR_LATER(ah)) { if (max_streams >= 2) ht_info->cap |= IEEE80211_HT_CAP_TX_STBC; ht_info->cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT); diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index c5e7af4f51ab..7b6f66bf3739 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -454,7 +454,7 @@ u32 ath_calcrxfilter(struct ath_softc *sc) else rfilt |= ATH9K_RX_FILTER_BEACON; - if ((AR_SREV_9280_10_OR_LATER(sc->sc_ah) || + if ((AR_SREV_9280_20_OR_LATER(sc->sc_ah) || AR_SREV_9285_10_OR_LATER(sc->sc_ah)) && (sc->sc_ah->opmode == NL80211_IFTYPE_AP) && (sc->rx.rxfilter & FIF_PSPOLL)) diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index d01c4adab8d6..cabfa0356c9c 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -819,15 +819,10 @@ ((_ah)->hw_version.macRev == AR_SREV_REVISION_9160_11)) #define AR_SREV_9280(_ah) \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9280)) -#define AR_SREV_9280_10_OR_LATER(_ah) \ +#define AR_SREV_9280_20_OR_LATER(_ah) \ (((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9280)) #define AR_SREV_9280_20(_ah) \ - (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9280) && \ - ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9280_20)) -#define AR_SREV_9280_20_OR_LATER(_ah) \ - (((_ah)->hw_version.macVersion > AR_SREV_VERSION_9280) || \ - (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9280) && \ - ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9280_20))) + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9280)) #define AR_SREV_9285(_ah) \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9285)) -- cgit v1.2.3 From e17f83eafd37129f9e09425136e59bc4333bdb9c Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 22 Sep 2010 12:34:53 +0200 Subject: ath9k_hw: simplify revision checks for AR9285 Since AR9285 v1.0 and v1.1 were never sold (and the initvals removed), its revision checks can be simplified similar to AR9280 Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar5008_phy.c | 2 +- drivers/net/wireless/ath/ath9k/ar9002_calib.c | 11 +---------- drivers/net/wireless/ath/ath9k/eeprom_4k.c | 6 ------ drivers/net/wireless/ath/ath9k/hw.c | 8 ++++---- drivers/net/wireless/ath/ath9k/recv.c | 2 +- drivers/net/wireless/ath/ath9k/reg.h | 16 +--------------- 6 files changed, 8 insertions(+), 37 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c index 9318ae736982..79dfe9dded52 100644 --- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c @@ -701,7 +701,7 @@ static void ar5008_hw_set_channel_regs(struct ath_hw *ah, u32 phymode; u32 enableDacFifo = 0; - if (AR_SREV_9285_10_OR_LATER(ah)) + if (AR_SREV_9285_12_OR_LATER(ah)) enableDacFifo = (REG_READ(ah, AR_PHY_TURBO) & AR_PHY_FC_ENABLE_DAC_FIFO); diff --git a/drivers/net/wireless/ath/ath9k/ar9002_calib.c b/drivers/net/wireless/ath/ath9k/ar9002_calib.c index dc64afeeaa12..5d0815145b78 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_calib.c @@ -567,11 +567,6 @@ static inline void ar9285_hw_pa_cal(struct ath_hw *ah, bool is_reset) AR5416_EEP_TXGAIN_HIGH_POWER) return; - if (AR_SREV_9285_11(ah)) { - REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14)); - udelay(10); - } - for (i = 0; i < ARRAY_SIZE(regList); i++) regList[i][1] = REG_READ(ah, regList[i][0]); @@ -651,10 +646,6 @@ static inline void ar9285_hw_pa_cal(struct ath_hw *ah, bool is_reset) REG_WRITE(ah, regList[i][0], regList[i][1]); REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, ccomp_org); - - if (AR_SREV_9285_11(ah)) - REG_WRITE(ah, AR9285_AN_TOP4, AR9285_AN_TOP4_DEFAULT); - } static void ar9002_hw_pa_cal(struct ath_hw *ah, bool is_reset) @@ -664,7 +655,7 @@ static void ar9002_hw_pa_cal(struct ath_hw *ah, bool is_reset) ar9271_hw_pa_cal(ah, is_reset); else ah->pacal_info.skipcount--; - } else if (AR_SREV_9285_11_OR_LATER(ah)) { + } else if (AR_SREV_9285_12_OR_LATER(ah)) { if (is_reset || !ah->pacal_info.skipcount) ar9285_hw_pa_cal(ah, is_reset); else diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c index 677e0c9d0481..d6eed1f02e84 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c @@ -909,9 +909,6 @@ static void ath9k_hw_4k_set_gain(struct ath_hw *ah, AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal); REG_RMW_FIELD(ah, AR_PHY_RXGAIN + 0x1000, AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]); - - if (AR_SREV_9285_11(ah)) - REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14)); } /* @@ -1109,9 +1106,6 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah, } - if (AR_SREV_9285_11(ah)) - REG_WRITE(ah, AR9285_AN_TOP4, AR9285_AN_TOP4_DEFAULT); - REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH, pModal->switchSettling); REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC, diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index f2255a211637..1f41b4513c52 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1190,7 +1190,7 @@ bool ath9k_hw_check_alive(struct ath_hw *ah) int count = 50; u32 reg; - if (AR_SREV_9285_10_OR_LATER(ah)) + if (AR_SREV_9285_12_OR_LATER(ah)) return true; do { @@ -1787,7 +1787,7 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) regulatory->current_rd = eeval; eeval = ah->eep_ops->get_eeprom(ah, EEP_REG_1); - if (AR_SREV_9285_10_OR_LATER(ah)) + if (AR_SREV_9285_12_OR_LATER(ah)) eeval |= AR9285_RDEXT_DEFAULT; regulatory->current_rd_ext = eeval; @@ -1893,7 +1893,7 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) pCap->num_gpio_pins = AR9271_NUM_GPIO; else if (AR_DEVID_7010(ah)) pCap->num_gpio_pins = AR7010_NUM_GPIO; - else if (AR_SREV_9285_10_OR_LATER(ah)) + else if (AR_SREV_9285_12_OR_LATER(ah)) pCap->num_gpio_pins = AR9285_NUM_GPIO; else if (AR_SREV_9280_20_OR_LATER(ah)) pCap->num_gpio_pins = AR928X_NUM_GPIO; @@ -2075,7 +2075,7 @@ u32 ath9k_hw_gpio_get(struct ath_hw *ah, u32 gpio) return MS_REG_READ(AR9271, gpio) != 0; else if (AR_SREV_9287_10_OR_LATER(ah)) return MS_REG_READ(AR9287, gpio) != 0; - else if (AR_SREV_9285_10_OR_LATER(ah)) + else if (AR_SREV_9285_12_OR_LATER(ah)) return MS_REG_READ(AR9285, gpio) != 0; else if (AR_SREV_9280_20_OR_LATER(ah)) return MS_REG_READ(AR928X, gpio) != 0; diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 7b6f66bf3739..00140489becb 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -455,7 +455,7 @@ u32 ath_calcrxfilter(struct ath_softc *sc) rfilt |= ATH9K_RX_FILTER_BEACON; if ((AR_SREV_9280_20_OR_LATER(sc->sc_ah) || - AR_SREV_9285_10_OR_LATER(sc->sc_ah)) && + AR_SREV_9285_12_OR_LATER(sc->sc_ah)) && (sc->sc_ah->opmode == NL80211_IFTYPE_AP) && (sc->rx.rxfilter & FIF_PSPOLL)) rfilt |= ATH9K_RX_FILTER_PSPOLL; diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index cabfa0356c9c..7ff814d4a792 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -826,22 +826,8 @@ #define AR_SREV_9285(_ah) \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9285)) -#define AR_SREV_9285_10_OR_LATER(_ah) \ - (((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9285)) -#define AR_SREV_9285_11(_ah) \ - (AR_SREV_9285(ah) && \ - ((_ah)->hw_version.macRev == AR_SREV_REVISION_9285_11)) -#define AR_SREV_9285_11_OR_LATER(_ah) \ - (((_ah)->hw_version.macVersion > AR_SREV_VERSION_9285) || \ - (AR_SREV_9285(ah) && ((_ah)->hw_version.macRev >= \ - AR_SREV_REVISION_9285_11))) -#define AR_SREV_9285_12(_ah) \ - (AR_SREV_9285(ah) && \ - ((_ah)->hw_version.macRev == AR_SREV_REVISION_9285_12)) #define AR_SREV_9285_12_OR_LATER(_ah) \ - (((_ah)->hw_version.macVersion > AR_SREV_VERSION_9285) || \ - (AR_SREV_9285(ah) && ((_ah)->hw_version.macRev >= \ - AR_SREV_REVISION_9285_12))) + (((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9285)) #define AR_SREV_9287(_ah) \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287)) -- cgit v1.2.3 From a42acef0dd3548ffda03d245d41b95250354017e Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 22 Sep 2010 12:34:54 +0200 Subject: ath9k_hw: simplify revision checks for AR9287 Since AR9287 v1.0 was never sold (and the initvals removed), its revision checks can be simplified similar to AR9280 Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar5008_phy.c | 6 +++--- drivers/net/wireless/ath/ath9k/ar9002_calib.c | 4 ++-- drivers/net/wireless/ath/ath9k/eeprom.h | 2 +- drivers/net/wireless/ath/ath9k/hw.c | 4 ++-- drivers/net/wireless/ath/ath9k/reg.h | 9 +-------- 5 files changed, 9 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c index 79dfe9dded52..525671f52b45 100644 --- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c @@ -669,7 +669,7 @@ static void ar5008_hw_override_ini(struct ath_hw *ah, if (!AR_SREV_9271(ah)) val &= ~AR_PCU_MISC_MODE2_HWWAR1; - if (AR_SREV_9287_10_OR_LATER(ah)) + if (AR_SREV_9287_11_OR_LATER(ah)) val = val & (~AR_PCU_MISC_MODE2_HWWAR2); REG_WRITE(ah, AR_PCU_MISC_MODE2, val); @@ -820,11 +820,11 @@ static int ar5008_hw_process_ini(struct ath_hw *ah, REGWRITE_BUFFER_FLUSH(ah); DISABLE_REGWRITE_BUFFER(ah); - if (AR_SREV_9280(ah) || AR_SREV_9287_10_OR_LATER(ah)) + if (AR_SREV_9280(ah) || AR_SREV_9287_11_OR_LATER(ah)) REG_WRITE_ARRAY(&ah->iniModesRxGain, modesIndex, regWrites); if (AR_SREV_9280(ah) || AR_SREV_9285_12_OR_LATER(ah) || - AR_SREV_9287_10_OR_LATER(ah)) + AR_SREV_9287_11_OR_LATER(ah)) REG_WRITE_ARRAY(&ah->iniModesTxGain, modesIndex, regWrites); if (AR_SREV_9271_10(ah)) diff --git a/drivers/net/wireless/ath/ath9k/ar9002_calib.c b/drivers/net/wireless/ath/ath9k/ar9002_calib.c index 5d0815145b78..d7d1d55362e6 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_calib.c @@ -833,7 +833,7 @@ static bool ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan) return false; } else { if (AR_SREV_9280_20_OR_LATER(ah)) { - if (!AR_SREV_9287_10_OR_LATER(ah)) + if (!AR_SREV_9287_11_OR_LATER(ah)) REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, @@ -856,7 +856,7 @@ static bool ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan) } if (AR_SREV_9280_20_OR_LATER(ah)) { - if (!AR_SREV_9287_10_OR_LATER(ah)) + if (!AR_SREV_9287_11_OR_LATER(ah)) REG_SET_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h index 3030564a0f21..dacb45e1b906 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.h +++ b/drivers/net/wireless/ath/ath9k/eeprom.h @@ -101,7 +101,7 @@ #define AR5416_VER_MASK (eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) #define OLC_FOR_AR9280_20_LATER (AR_SREV_9280_20_OR_LATER(ah) && \ ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL)) -#define OLC_FOR_AR9287_10_LATER (AR_SREV_9287_10_OR_LATER(ah) && \ +#define OLC_FOR_AR9287_10_LATER (AR_SREV_9287_11_OR_LATER(ah) && \ ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL)) #define AR_EEPROM_RFSILENT_GPIO_SEL 0x001c diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 1f41b4513c52..25ed65ac992c 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1989,7 +1989,7 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) if (AR_SREV_9300_20_OR_LATER(ah)) pCap->hw_caps |= ATH9K_HW_CAP_RAC_SUPPORTED; - if (AR_SREV_9287_10_OR_LATER(ah) || AR_SREV_9271(ah)) + if (AR_SREV_9287_11_OR_LATER(ah) || AR_SREV_9271(ah)) pCap->hw_caps |= ATH9K_HW_CAP_SGI_20; if (AR_SREV_9285(ah)) @@ -2073,7 +2073,7 @@ u32 ath9k_hw_gpio_get(struct ath_hw *ah, u32 gpio) return MS_REG_READ(AR9300, gpio) != 0; else if (AR_SREV_9271(ah)) return MS_REG_READ(AR9271, gpio) != 0; - else if (AR_SREV_9287_10_OR_LATER(ah)) + else if (AR_SREV_9287_11_OR_LATER(ah)) return MS_REG_READ(AR9287, gpio) != 0; else if (AR_SREV_9285_12_OR_LATER(ah)) return MS_REG_READ(AR9285, gpio) != 0; diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 7ff814d4a792..6d01e501b9b4 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -831,18 +831,11 @@ #define AR_SREV_9287(_ah) \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287)) -#define AR_SREV_9287_10_OR_LATER(_ah) \ +#define AR_SREV_9287_11_OR_LATER(_ah) \ (((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9287)) -#define AR_SREV_9287_10(_ah) \ - (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287) && \ - ((_ah)->hw_version.macRev == AR_SREV_REVISION_9287_10)) #define AR_SREV_9287_11(_ah) \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287) && \ ((_ah)->hw_version.macRev == AR_SREV_REVISION_9287_11)) -#define AR_SREV_9287_11_OR_LATER(_ah) \ - (((_ah)->hw_version.macVersion > AR_SREV_VERSION_9287) || \ - (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287) && \ - ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9287_11))) #define AR_SREV_9287_12(_ah) \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287) && \ ((_ah)->hw_version.macRev == AR_SREV_REVISION_9287_12)) -- cgit v1.2.3 From 295bafb47b0d365e1b4f747dffef29e590f13233 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Wed, 22 Sep 2010 20:29:01 -0700 Subject: mac80211: Support multiple VIFS per AP in debugfs. Create 'stations' sub-directory under each netdev:[vif-name] directory to hold all stations for that network device. Signed-off-by: Ben Greear Acked-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/debugfs.c | 1 - net/mac80211/debugfs_netdev.c | 3 +++ net/mac80211/debugfs_sta.c | 2 +- net/mac80211/ieee80211_i.h | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index e81ef4e8cb32..ebd5b69f562e 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -368,7 +368,6 @@ void debugfs_hw_add(struct ieee80211_local *local) if (!phyd) return; - local->debugfs.stations = debugfs_create_dir("stations", phyd); local->debugfs.keys = debugfs_create_dir("keys", phyd); DEBUGFS_ADD(frequency); diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 20b2998fa0ed..3e12430591b7 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -409,6 +409,9 @@ void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata) sprintf(buf, "netdev:%s", sdata->name); sdata->debugfs.dir = debugfs_create_dir(buf, sdata->local->hw.wiphy->debugfsdir); + if (sdata->debugfs.dir) + sdata->debugfs.subdir_stations = debugfs_create_dir("stations", + sdata->debugfs.dir); add_files(sdata); } diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 76839d4dfaac..6b7ff9fb4604 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -300,7 +300,7 @@ STA_OPS(ht_capa); void ieee80211_sta_debugfs_add(struct sta_info *sta) { - struct dentry *stations_dir = sta->local->debugfs.stations; + struct dentry *stations_dir = sta->sdata->debugfs.subdir_stations; u8 mac[3*ETH_ALEN]; sta->debugfs.add_has_run = true; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 78a8d9208cec..40f747273389 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -564,6 +564,7 @@ struct ieee80211_sub_if_data { #ifdef CONFIG_MAC80211_DEBUGFS struct { struct dentry *dir; + struct dentry *subdir_stations; struct dentry *default_key; struct dentry *default_mgmt_key; } debugfs; @@ -899,7 +900,6 @@ struct ieee80211_local { #ifdef CONFIG_MAC80211_DEBUGFS struct local_debugfsdentries { struct dentry *rcdir; - struct dentry *stations; struct dentry *keys; } debugfs; #endif -- cgit v1.2.3 From 686b9cb994f5f74be790df4cd12873dfdc8a6984 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Thu, 23 Sep 2010 09:44:36 -0700 Subject: mac80211/ath9k: Support AMPDU with multiple VIFs. The old ieee80211_find_sta_by_hw method didn't properly find VIFS when there was more than one per AP. This caused AMPDU logic in ath9k to get the wrong VIF when trying to account for transmitted SKBs. This patch changes ieee80211_find_sta_by_hw to take a localaddr argument to distinguish between VIFs with the same AP but different local addresses. The method name is changed to ieee80211_find_sta_by_ifaddr. Signed-off-by: Ben Greear Acked-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/recv.c | 6 +++++- drivers/net/wireless/ath/ath9k/xmit.c | 3 +-- include/net/mac80211.h | 25 ++++++++++++++----------- net/mac80211/sta_info.c | 15 +++++++++++---- 4 files changed, 31 insertions(+), 18 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 00140489becb..9c166f3804ab 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -977,7 +977,11 @@ static void ath9k_process_rssi(struct ath_common *common, * at least one sdata of a wiphy on mac80211 but with ath9k virtual * wiphy you'd have to iterate over every wiphy and each sdata. */ - sta = ieee80211_find_sta_by_hw(hw, hdr->addr2); + if (is_multicast_ether_addr(hdr->addr1)) + sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr2, NULL); + else + sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr2, hdr->addr1); + if (sta) { an = (struct ath_node *) sta->drv_priv; if (rx_stats->rs_rssi != ATH9K_RSSI_BAD && diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 85a7323a04ef..f7da6b20a925 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -328,8 +328,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, rcu_read_lock(); - /* XXX: use ieee80211_find_sta! */ - sta = ieee80211_find_sta_by_hw(hw, hdr->addr1); + sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr1, hdr->addr2); if (!sta) { rcu_read_unlock(); diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 5d1187d7c5e5..73469d8b64bb 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -2432,25 +2432,28 @@ struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_vif *vif, const u8 *addr); /** - * ieee80211_find_sta_by_hw - find a station on hardware + * ieee80211_find_sta_by_ifaddr - find a station on hardware * * @hw: pointer as obtained from ieee80211_alloc_hw() - * @addr: station's address + * @addr: remote station's address + * @localaddr: local address (vif->sdata->vif.addr). Use NULL for 'any'. * * This function must be called under RCU lock and the * resulting pointer is only valid under RCU lock as well. * - * NOTE: This function should not be used! When mac80211 is converted - * internally to properly keep track of stations on multiple - * virtual interfaces, it will not always know which station to - * return here since a single address might be used by multiple - * logical stations (e.g. consider a station connecting to another - * BSSID on the same AP hardware without disconnecting first). + * NOTE: You may pass NULL for localaddr, but then you will just get + * the first STA that matches the remote address 'addr'. + * We can have multiple STA associated with multiple + * logical stations (e.g. consider a station connecting to another + * BSSID on the same AP hardware without disconnecting first). + * In this case, the result of this method with localaddr NULL + * is not reliable. * - * DO NOT USE THIS FUNCTION. + * DO NOT USE THIS FUNCTION with localaddr NULL if at all possible. */ -struct ieee80211_sta *ieee80211_find_sta_by_hw(struct ieee80211_hw *hw, - const u8 *addr); +struct ieee80211_sta *ieee80211_find_sta_by_ifaddr(struct ieee80211_hw *hw, + const u8 *addr, + const u8 *localaddr); /** * ieee80211_sta_block_awake - block station from waking up diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 44e10a9de0a7..ca2cba9cea87 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -838,13 +838,20 @@ void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata, mutex_unlock(&local->sta_mtx); } -struct ieee80211_sta *ieee80211_find_sta_by_hw(struct ieee80211_hw *hw, - const u8 *addr) +struct ieee80211_sta *ieee80211_find_sta_by_ifaddr(struct ieee80211_hw *hw, + const u8 *addr, + const u8 *localaddr) { struct sta_info *sta, *nxt; - /* Just return a random station ... first in list ... */ + /* + * Just return a random station if localaddr is NULL + * ... first in list. + */ for_each_sta_info(hw_to_local(hw), addr, sta, nxt) { + if (localaddr && + compare_ether_addr(sta->sdata->vif.addr, localaddr) != 0) + continue; if (!sta->uploaded) return NULL; return &sta->sta; @@ -852,7 +859,7 @@ struct ieee80211_sta *ieee80211_find_sta_by_hw(struct ieee80211_hw *hw, return NULL; } -EXPORT_SYMBOL_GPL(ieee80211_find_sta_by_hw); +EXPORT_SYMBOL_GPL(ieee80211_find_sta_by_ifaddr); struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_vif *vif, const u8 *addr) -- cgit v1.2.3 From 56af326830757f3e8a1742770d15dfd6e3c40e85 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Thu, 23 Sep 2010 10:22:24 -0700 Subject: mac80211: Support receiving data frames on multiple vifs. When using multiple STA interfaces on the same radio, some data packets need to be received on all interfaces (broadcast, for instance). Make the STA loop look similar to the mgt-data loop. Also, add logic to check RX_FLAG_MMIC_ERROR for last interface in mgt-data loop. Signed-off-by: Ben Greear Acked-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/rx.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 70 insertions(+), 10 deletions(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 308e502a80eb..50c0803a63ba 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2609,7 +2609,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, int prepares; struct ieee80211_sub_if_data *prev = NULL; struct sk_buff *skb_new; - struct sta_info *sta, *tmp; + struct sta_info *sta, *tmp, *prev_sta; bool found_sta = false; int err = 0; @@ -2640,22 +2640,74 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, ieee80211_verify_alignment(&rx); if (ieee80211_is_data(fc)) { + prev_sta = NULL; for_each_sta_info(local, hdr->addr2, sta, tmp) { - rx.sta = sta; found_sta = true; - rx.sdata = sta->sdata; + if (!prev_sta) { + prev_sta = sta; + continue; + } + + rx.sta = prev_sta; + rx.sdata = prev_sta->sdata; rx.flags |= IEEE80211_RX_RA_MATCH; prepares = prepare_for_handlers(rx.sdata, &rx, hdr); - if (prepares) { - if (status->flag & RX_FLAG_MMIC_ERROR) { - if (rx.flags & IEEE80211_RX_RA_MATCH) - ieee80211_rx_michael_mic_report(hdr, &rx); - } else - prev = rx.sdata; + if (!prepares) + goto next_sta; + + if (status->flag & RX_FLAG_MMIC_ERROR) { + if (rx.flags & IEEE80211_RX_RA_MATCH) + ieee80211_rx_michael_mic_report(hdr, &rx); + goto next_sta; + } + + /* + * frame was destined for the previous interface + * so invoke RX handlers for it + */ + skb_new = skb_copy(skb, GFP_ATOMIC); + if (!skb_new) { + if (net_ratelimit()) + wiphy_debug(local->hw.wiphy, + "failed to copy multicast" + " frame for %s\n", + prev_sta->sdata->name); + goto next_sta; + } + ieee80211_invoke_rx_handlers(prev_sta->sdata, &rx, + skb_new); +next_sta: + prev_sta = sta; + } /* for all STA info */ + + if (prev_sta) { + rx.sta = prev_sta; + rx.sdata = prev_sta->sdata; + + rx.flags |= IEEE80211_RX_RA_MATCH; + prepares = prepare_for_handlers(rx.sdata, &rx, hdr); + if (!prepares) + prev_sta = NULL; + + if (prev_sta && status->flag & RX_FLAG_MMIC_ERROR) { + if (rx.flags & IEEE80211_RX_RA_MATCH) + ieee80211_rx_michael_mic_report(hdr, &rx); + prev_sta = NULL; } } - } + + + if (prev_sta) { + ieee80211_invoke_rx_handlers(prev_sta->sdata, &rx, skb); + return; + } else { + if (found_sta) { + dev_kfree_skb(skb); + return; + } + } + } /* if data frame */ if (!found_sta) { list_for_each_entry_rcu(sdata, &local->interfaces, list) { if (!ieee80211_sdata_running(sdata)) @@ -2718,6 +2770,14 @@ next: if (!prepares) prev = NULL; + + if (prev && status->flag & RX_FLAG_MMIC_ERROR) { + rx.sdata = prev; + if (rx.flags & IEEE80211_RX_RA_MATCH) + ieee80211_rx_michael_mic_report(hdr, + &rx); + prev = NULL; + } } } if (prev) -- cgit v1.2.3 From 92e44948b2b3b2db8f39f17033f98ae2356156a5 Mon Sep 17 00:00:00 2001 From: Teemu Paasikivi Date: Fri, 24 Sep 2010 07:23:55 +0300 Subject: nl80211: Fix exit from nl80211_set_power_save If interface does not existk, when nl80211_set_power_save is called, (eg. module has been unloaded) it has been causing kernel panic. Added new goto target to avoid crash if get_rdev_dev_by_info_ifindex does not return dev and rdev pointers. Signed-off-by: Teemu Paasikivi Signed-off-by: John W. Linville --- net/wireless/nl80211.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index f15b1af2c768..4ff827e8c362 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -4990,7 +4990,7 @@ static int nl80211_set_power_save(struct sk_buff *skb, struct genl_info *info) err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) - goto unlock_rdev; + goto unlock_rtnl; wdev = dev->ieee80211_ptr; @@ -5014,6 +5014,7 @@ static int nl80211_set_power_save(struct sk_buff *skb, struct genl_info *info) unlock_rdev: cfg80211_unlock_rdev(rdev); dev_put(dev); +unlock_rtnl: rtnl_unlock(); out: -- cgit v1.2.3 From 7c1e183186377e84e6f4e457be0514887f2df4ef Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Fri, 24 Sep 2010 15:52:49 -0400 Subject: Revert "mac80211: fix use-after-free" This reverts commit cd87a2d3a33d75a646f1aa1aa2ee5bf712d6f963. Author reports it conflicts with proper fixes, applied hereafter. Signed-off-by: John W. Linville --- net/mac80211/rx.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 50c0803a63ba..29a582df6371 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2286,6 +2286,9 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx, struct net_device *prev_dev = NULL; struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); + if (status->flag & RX_FLAG_INTERNAL_CMTR) + goto out_free_skb; + if (skb_headroom(skb) < sizeof(*rthdr) && pskb_expand_head(skb, sizeof(*rthdr), 0, GFP_ATOMIC)) goto out_free_skb; @@ -2344,6 +2347,7 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx, } else goto out_free_skb; + status->flag |= RX_FLAG_INTERNAL_CMTR; return; out_free_skb: -- cgit v1.2.3 From 20b01f80f72426e7ed2e773220da4357925383d5 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 24 Sep 2010 11:21:05 +0200 Subject: mac80211: remove prepare_for_handlers sdata argument The first argument to prepare_for_handlers is always the sdata that can just be stored in rx data directly (and even already is, in two of four code paths.) Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/rx.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 29a582df6371..f59f6f51e39c 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2513,10 +2513,10 @@ void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid) /* main receive path */ -static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, - struct ieee80211_rx_data *rx, +static int prepare_for_handlers(struct ieee80211_rx_data *rx, struct ieee80211_hdr *hdr) { + struct ieee80211_sub_if_data *sdata = rx->sdata; struct sk_buff *skb = rx->skb; struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); u8 *bssid = ieee80211_get_bssid(hdr, skb->len, sdata->vif.type); @@ -2656,7 +2656,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, rx.sdata = prev_sta->sdata; rx.flags |= IEEE80211_RX_RA_MATCH; - prepares = prepare_for_handlers(rx.sdata, &rx, hdr); + prepares = prepare_for_handlers(&rx, hdr); if (!prepares) goto next_sta; @@ -2690,7 +2690,7 @@ next_sta: rx.sdata = prev_sta->sdata; rx.flags |= IEEE80211_RX_RA_MATCH; - prepares = prepare_for_handlers(rx.sdata, &rx, hdr); + prepares = prepare_for_handlers(&rx, hdr); if (!prepares) prev_sta = NULL; @@ -2733,15 +2733,15 @@ next_sta: } rx.sta = sta_info_get_bss(prev, hdr->addr2); + rx.sdata = prev; rx.flags |= IEEE80211_RX_RA_MATCH; - prepares = prepare_for_handlers(prev, &rx, hdr); + prepares = prepare_for_handlers(&rx, hdr); if (!prepares) goto next; if (status->flag & RX_FLAG_MMIC_ERROR) { - rx.sdata = prev; if (rx.flags & IEEE80211_RX_RA_MATCH) ieee80211_rx_michael_mic_report(hdr, &rx); @@ -2768,15 +2768,15 @@ next: if (prev) { rx.sta = sta_info_get_bss(prev, hdr->addr2); + rx.sdata = prev; rx.flags |= IEEE80211_RX_RA_MATCH; - prepares = prepare_for_handlers(prev, &rx, hdr); + prepares = prepare_for_handlers(&rx, hdr); if (!prepares) prev = NULL; if (prev && status->flag & RX_FLAG_MMIC_ERROR) { - rx.sdata = prev; if (rx.flags & IEEE80211_RX_RA_MATCH) ieee80211_rx_michael_mic_report(hdr, &rx); -- cgit v1.2.3 From 4406c376895608375105013bf405ecac720ef558 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 24 Sep 2010 11:21:06 +0200 Subject: mac80211: consolidate packet processing There are now four instances of vaguely the same code that does packet preparation, checking for MMIC errors and reporting them, and then invoking packet processing. Consolidate all of these. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/rx.c | 165 ++++++++++++++++++++---------------------------------- 1 file changed, 62 insertions(+), 103 deletions(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index f59f6f51e39c..13311f8960ab 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2443,18 +2443,13 @@ static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx, } } -static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata, - struct ieee80211_rx_data *rx, - struct sk_buff *skb) +static void ieee80211_invoke_rx_handlers(struct ieee80211_rx_data *rx) { struct sk_buff_head reorder_release; ieee80211_rx_result res = RX_DROP_MONITOR; __skb_queue_head_init(&reorder_release); - rx->skb = skb; - rx->sdata = sdata; - #define CALL_RXH(rxh) \ do { \ res = rxh(rx); \ @@ -2597,6 +2592,51 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx, return 1; } +/* + * This function returns whether or not the SKB + * was destined for RX processing or not, which, + * if consume is true, is equivalent to whether + * or not the skb was consumed. + */ +static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx, + struct sk_buff *skb, bool consume) +{ + struct ieee80211_local *local = rx->local; + struct ieee80211_sub_if_data *sdata = rx->sdata; + struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); + struct ieee80211_hdr *hdr = (void *)skb->data; + int prepares; + + rx->skb = skb; + rx->flags |= IEEE80211_RX_RA_MATCH; + prepares = prepare_for_handlers(rx, hdr); + + if (!prepares) + return false; + + if (status->flag & RX_FLAG_MMIC_ERROR) { + if (rx->flags & IEEE80211_RX_RA_MATCH) + ieee80211_rx_michael_mic_report(hdr, rx); + return false; + } + + if (!consume) { + skb = skb_copy(skb, GFP_ATOMIC); + if (!skb) { + if (net_ratelimit()) + wiphy_debug(local->hw.wiphy, + "failed to copy multicast frame for %s\n", + sdata->name); + return true; + } + + rx->skb = skb; + } + + ieee80211_invoke_rx_handlers(rx); + return true; +} + /* * This is the actual Rx frames handler. as it blongs to Rx path it must * be called with rcu_read_lock protection. @@ -2604,15 +2644,12 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx, static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, struct sk_buff *skb) { - struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_sub_if_data *sdata; struct ieee80211_hdr *hdr; __le16 fc; struct ieee80211_rx_data rx; - int prepares; - struct ieee80211_sub_if_data *prev = NULL; - struct sk_buff *skb_new; + struct ieee80211_sub_if_data *prev; struct sta_info *sta, *tmp, *prev_sta; bool found_sta = false; int err = 0; @@ -2645,8 +2682,10 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, if (ieee80211_is_data(fc)) { prev_sta = NULL; + for_each_sta_info(local, hdr->addr2, sta, tmp) { found_sta = true; + if (!prev_sta) { prev_sta = sta; continue; @@ -2654,65 +2693,23 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, rx.sta = prev_sta; rx.sdata = prev_sta->sdata; + ieee80211_prepare_and_rx_handle(&rx, skb, false); - rx.flags |= IEEE80211_RX_RA_MATCH; - prepares = prepare_for_handlers(&rx, hdr); - if (!prepares) - goto next_sta; - - if (status->flag & RX_FLAG_MMIC_ERROR) { - if (rx.flags & IEEE80211_RX_RA_MATCH) - ieee80211_rx_michael_mic_report(hdr, &rx); - goto next_sta; - } - - /* - * frame was destined for the previous interface - * so invoke RX handlers for it - */ - skb_new = skb_copy(skb, GFP_ATOMIC); - if (!skb_new) { - if (net_ratelimit()) - wiphy_debug(local->hw.wiphy, - "failed to copy multicast" - " frame for %s\n", - prev_sta->sdata->name); - goto next_sta; - } - ieee80211_invoke_rx_handlers(prev_sta->sdata, &rx, - skb_new); -next_sta: prev_sta = sta; - } /* for all STA info */ + } if (prev_sta) { rx.sta = prev_sta; rx.sdata = prev_sta->sdata; - rx.flags |= IEEE80211_RX_RA_MATCH; - prepares = prepare_for_handlers(&rx, hdr); - if (!prepares) - prev_sta = NULL; - - if (prev_sta && status->flag & RX_FLAG_MMIC_ERROR) { - if (rx.flags & IEEE80211_RX_RA_MATCH) - ieee80211_rx_michael_mic_report(hdr, &rx); - prev_sta = NULL; - } - } - - - if (prev_sta) { - ieee80211_invoke_rx_handlers(prev_sta->sdata, &rx, skb); - return; - } else { - if (found_sta) { - dev_kfree_skb(skb); + if (ieee80211_prepare_and_rx_handle(&rx, skb, true)) return; - } } - } /* if data frame */ + } + if (!found_sta) { + prev = NULL; + list_for_each_entry_rcu(sdata, &local->interfaces, list) { if (!ieee80211_sdata_running(sdata)) continue; @@ -2734,35 +2731,8 @@ next_sta: rx.sta = sta_info_get_bss(prev, hdr->addr2); rx.sdata = prev; + ieee80211_prepare_and_rx_handle(&rx, skb, false); - rx.flags |= IEEE80211_RX_RA_MATCH; - prepares = prepare_for_handlers(&rx, hdr); - - if (!prepares) - goto next; - - if (status->flag & RX_FLAG_MMIC_ERROR) { - if (rx.flags & IEEE80211_RX_RA_MATCH) - ieee80211_rx_michael_mic_report(hdr, - &rx); - goto next; - } - - /* - * frame was destined for the previous interface - * so invoke RX handlers for it - */ - - skb_new = skb_copy(skb, GFP_ATOMIC); - if (!skb_new) { - if (net_ratelimit()) - wiphy_debug(local->hw.wiphy, - "failed to copy multicast frame for %s\n", - prev->name); - goto next; - } - ieee80211_invoke_rx_handlers(prev, &rx, skb_new); -next: prev = sdata; } @@ -2770,24 +2740,13 @@ next: rx.sta = sta_info_get_bss(prev, hdr->addr2); rx.sdata = prev; - rx.flags |= IEEE80211_RX_RA_MATCH; - prepares = prepare_for_handlers(&rx, hdr); - - if (!prepares) - prev = NULL; - - if (prev && status->flag & RX_FLAG_MMIC_ERROR) { - if (rx.flags & IEEE80211_RX_RA_MATCH) - ieee80211_rx_michael_mic_report(hdr, - &rx); - prev = NULL; - } + if (ieee80211_prepare_and_rx_handle(&rx, skb, true)) + return; } + } - if (prev) - ieee80211_invoke_rx_handlers(prev, &rx, skb); - else - dev_kfree_skb(skb); + + dev_kfree_skb(skb); } /* -- cgit v1.2.3 From 4b0dd98e70b6516c2c26f28091c2fb09f0ecf215 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 24 Sep 2010 11:21:07 +0200 Subject: mac80211: clean up rx handling wrt. found_sta If a station was found, then we'll have exited the function already, so it is not necessary to have a variable keeping track of it. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/rx.c | 56 +++++++++++++++++++++++++------------------------------ 1 file changed, 25 insertions(+), 31 deletions(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 13311f8960ab..2b6b4eab44dd 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2651,7 +2651,6 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, struct ieee80211_rx_data rx; struct ieee80211_sub_if_data *prev; struct sta_info *sta, *tmp, *prev_sta; - bool found_sta = false; int err = 0; fc = ((struct ieee80211_hdr *)skb->data)->frame_control; @@ -2684,8 +2683,6 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, prev_sta = NULL; for_each_sta_info(local, hdr->addr2, sta, tmp) { - found_sta = true; - if (!prev_sta) { prev_sta = sta; continue; @@ -2707,43 +2704,40 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, } } - if (!found_sta) { - prev = NULL; - - list_for_each_entry_rcu(sdata, &local->interfaces, list) { - if (!ieee80211_sdata_running(sdata)) - continue; - - if (sdata->vif.type == NL80211_IFTYPE_MONITOR || - sdata->vif.type == NL80211_IFTYPE_AP_VLAN) - continue; + prev = NULL; - /* - * frame is destined for this interface, but if it's - * not also for the previous one we handle that after - * the loop to avoid copying the SKB once too much - */ + list_for_each_entry_rcu(sdata, &local->interfaces, list) { + if (!ieee80211_sdata_running(sdata)) + continue; - if (!prev) { - prev = sdata; - continue; - } + if (sdata->vif.type == NL80211_IFTYPE_MONITOR || + sdata->vif.type == NL80211_IFTYPE_AP_VLAN) + continue; - rx.sta = sta_info_get_bss(prev, hdr->addr2); - rx.sdata = prev; - ieee80211_prepare_and_rx_handle(&rx, skb, false); + /* + * frame is destined for this interface, but if it's + * not also for the previous one we handle that after + * the loop to avoid copying the SKB once too much + */ + if (!prev) { prev = sdata; + continue; } - if (prev) { - rx.sta = sta_info_get_bss(prev, hdr->addr2); - rx.sdata = prev; + rx.sta = sta_info_get_bss(prev, hdr->addr2); + rx.sdata = prev; + ieee80211_prepare_and_rx_handle(&rx, skb, false); - if (ieee80211_prepare_and_rx_handle(&rx, skb, true)) - return; - } + prev = sdata; + } + + if (prev) { + rx.sta = sta_info_get_bss(prev, hdr->addr2); + rx.sdata = prev; + if (ieee80211_prepare_and_rx_handle(&rx, skb, true)) + return; } dev_kfree_skb(skb); -- cgit v1.2.3 From 4080c7cdc23f26c6e6166a70f50fa43814552d81 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 24 Sep 2010 11:21:08 +0200 Subject: mac80211: fix release_reorder_timeout in scan Even if the reorder timeout timer fires while scanning, the frames weren't received during scanning and therefore shouldn't be dropped. To implement this, changes to the passive scan RX handler simplify understanding it, because it currently checks HW_SCANNING independently of a packet's in-scan receive status (which doesn't make a big difference, since scan_rx() will only pick up probe responses and beacons, which can't be aggregated.) Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/rx.c | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 2b6b4eab44dd..8c666e9e8fb0 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -389,24 +389,22 @@ ieee80211_rx_h_passive_scan(struct ieee80211_rx_data *rx) struct ieee80211_local *local = rx->local; struct sk_buff *skb = rx->skb; - if (unlikely(test_bit(SCAN_HW_SCANNING, &local->scanning))) + if (likely(!(rx->flags & IEEE80211_RX_IN_SCAN))) + return RX_CONTINUE; + + if (test_bit(SCAN_HW_SCANNING, &local->scanning)) return ieee80211_scan_rx(rx->sdata, skb); - if (unlikely(test_bit(SCAN_SW_SCANNING, &local->scanning) && - (rx->flags & IEEE80211_RX_IN_SCAN))) { + if (test_bit(SCAN_SW_SCANNING, &local->scanning)) { /* drop all the other packets during a software scan anyway */ if (ieee80211_scan_rx(rx->sdata, skb) != RX_QUEUED) dev_kfree_skb(skb); return RX_QUEUED; } - if (unlikely(rx->flags & IEEE80211_RX_IN_SCAN)) { - /* scanning finished during invoking of handlers */ - I802_DEBUG_INC(local->rx_handlers_drop_passive_scan); - return RX_DROP_UNUSABLE; - } - - return RX_CONTINUE; + /* scanning finished during invoking of handlers */ + I802_DEBUG_INC(local->rx_handlers_drop_passive_scan); + return RX_DROP_UNUSABLE; } @@ -2495,10 +2493,6 @@ void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid) rx.queue = tid; rx.flags |= IEEE80211_RX_RA_MATCH; - if (unlikely(test_bit(SCAN_HW_SCANNING, &sta->local->scanning) || - test_bit(SCAN_OFF_CHANNEL, &sta->local->scanning))) - rx.flags |= IEEE80211_RX_IN_SCAN; - spin_lock(&tid_agg_rx->reorder_lock); ieee80211_sta_reorder_release(&sta->local->hw, tid_agg_rx, &frames); spin_unlock(&tid_agg_rx->reorder_lock); -- cgit v1.2.3 From 554891e63a29af35cc6bb403ef34e319518114d0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 24 Sep 2010 12:38:25 +0200 Subject: mac80211: move packet flags into packet commit 8c0c709eea5cbab97fb464cd68b06f24acc58ee1 Author: Johannes Berg Date: Wed Nov 25 17:46:15 2009 +0100 mac80211: move cmntr flag out of rx flags moved the CMNTR flag into the skb RX flags for some aggregation cleanups, but this was wrong since the optimisation this flag tried to make requires that it is kept across the processing of multiple interfaces -- which isn't true for flags in the skb. The patch not only broke the optimisation, it also introduced a bug: under some (common!) circumstances the flag will be set on an already freed skb! However, investigating this in more detail, I found that most of the flags that we set should be per packet, _except_ for this one, due to a-MPDU processing. Additionally, the flags used for processing (currently just this one) need to be reset before processing a new packet. Since we haven't actually seen bugs reported as a result of the wrong flags handling (which is not too surprising -- the only real bug case I can come up with is an a-MSDU contained in an a-MPDU), I'll make a different fix for rc. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- include/net/mac80211.h | 6 +-- net/mac80211/ieee80211_i.h | 38 +++++++++++++---- net/mac80211/rx.c | 102 +++++++++++++++++++++++++-------------------- net/mac80211/wpa.c | 2 +- 4 files changed, 91 insertions(+), 57 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 73469d8b64bb..fe8b9dae4dee 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -581,9 +581,6 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info) * @RX_FLAG_HT: HT MCS was used and rate_idx is MCS index * @RX_FLAG_40MHZ: HT40 (40 MHz) was used * @RX_FLAG_SHORT_GI: Short guard interval was used - * @RX_FLAG_INTERNAL_CMTR: set internally after frame was reported - * on cooked monitor to avoid double-reporting it for multiple - * virtual interfaces */ enum mac80211_rx_flags { RX_FLAG_MMIC_ERROR = 1<<0, @@ -597,7 +594,6 @@ enum mac80211_rx_flags { RX_FLAG_HT = 1<<9, RX_FLAG_40MHZ = 1<<10, RX_FLAG_SHORT_GI = 1<<11, - RX_FLAG_INTERNAL_CMTR = 1<<12, }; /** @@ -618,6 +614,7 @@ enum mac80211_rx_flags { * @rate_idx: index of data rate into band's supported rates or MCS index if * HT rates are use (RX_FLAG_HT) * @flag: %RX_FLAG_* + * @rx_flags: internal RX flags for mac80211 */ struct ieee80211_rx_status { u64 mactime; @@ -627,6 +624,7 @@ struct ieee80211_rx_status { int antenna; int rate_idx; int flag; + unsigned int rx_flags; }; /** diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 40f747273389..945fbf29719d 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -159,13 +159,37 @@ typedef unsigned __bitwise__ ieee80211_rx_result; #define RX_DROP_MONITOR ((__force ieee80211_rx_result) 2u) #define RX_QUEUED ((__force ieee80211_rx_result) 3u) -#define IEEE80211_RX_IN_SCAN BIT(0) -/* frame is destined to interface currently processed (incl. multicast frames) */ -#define IEEE80211_RX_RA_MATCH BIT(1) -#define IEEE80211_RX_AMSDU BIT(2) -#define IEEE80211_RX_FRAGMENTED BIT(3) -#define IEEE80211_MALFORMED_ACTION_FRM BIT(4) -/* only add flags here that do not change with subframes of an aMPDU */ +/** + * enum ieee80211_packet_rx_flags - packet RX flags + * @IEEE80211_RX_RA_MATCH: frame is destined to interface currently processed + * (incl. multicast frames) + * @IEEE80211_RX_IN_SCAN: received while scanning + * @IEEE80211_RX_FRAGMENTED: fragmented frame + * @IEEE80211_RX_AMSDU: a-MSDU packet + * @IEEE80211_RX_MALFORMED_ACTION_FRM: action frame is malformed + * + * These are per-frame flags that are attached to a frame in the + * @rx_flags field of &struct ieee80211_rx_status. + */ +enum ieee80211_packet_rx_flags { + IEEE80211_RX_IN_SCAN = BIT(0), + IEEE80211_RX_RA_MATCH = BIT(1), + IEEE80211_RX_FRAGMENTED = BIT(2), + IEEE80211_RX_AMSDU = BIT(3), + IEEE80211_RX_MALFORMED_ACTION_FRM = BIT(4), +}; + +/** + * enum ieee80211_rx_flags - RX data flags + * + * @IEEE80211_RX_CMNTR: received on cooked monitor already + * + * These flags are used across handling multiple interfaces + * for a single frame. + */ +enum ieee80211_rx_flags { + IEEE80211_RX_CMNTR = BIT(0), +}; struct ieee80211_rx_data { struct sk_buff *skb; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 8c666e9e8fb0..0b0e83ebe3d5 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -315,6 +315,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, static void ieee80211_parse_qos(struct ieee80211_rx_data *rx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; + struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); int tid; /* does the frame have a qos control field? */ @@ -323,9 +324,7 @@ static void ieee80211_parse_qos(struct ieee80211_rx_data *rx) /* frame has qos control */ tid = *qc & IEEE80211_QOS_CTL_TID_MASK; if (*qc & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT) - rx->flags |= IEEE80211_RX_AMSDU; - else - rx->flags &= ~IEEE80211_RX_AMSDU; + status->rx_flags |= IEEE80211_RX_AMSDU; } else { /* * IEEE 802.11-2007, 7.1.3.4.1 ("Sequence Number field"): @@ -387,9 +386,10 @@ static ieee80211_rx_result debug_noinline ieee80211_rx_h_passive_scan(struct ieee80211_rx_data *rx) { struct ieee80211_local *local = rx->local; + struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); struct sk_buff *skb = rx->skb; - if (likely(!(rx->flags & IEEE80211_RX_IN_SCAN))) + if (likely(!(status->rx_flags & IEEE80211_RX_IN_SCAN))) return RX_CONTINUE; if (test_bit(SCAN_HW_SCANNING, &local->scanning)) @@ -783,13 +783,14 @@ static ieee80211_rx_result debug_noinline ieee80211_rx_h_check(struct ieee80211_rx_data *rx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; + struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); /* Drop duplicate 802.11 retransmissions (IEEE 802.11 Chap. 9.2.9) */ if (rx->sta && !is_multicast_ether_addr(hdr->addr1)) { if (unlikely(ieee80211_has_retry(hdr->frame_control) && rx->sta->last_seq_ctrl[rx->queue] == hdr->seq_ctrl)) { - if (rx->flags & IEEE80211_RX_RA_MATCH) { + if (status->rx_flags & IEEE80211_RX_RA_MATCH) { rx->local->dot11FrameDuplicateCount++; rx->sta->num_duplicates++; } @@ -822,7 +823,7 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx) if ((!ieee80211_has_fromds(hdr->frame_control) && !ieee80211_has_tods(hdr->frame_control) && ieee80211_is_data(hdr->frame_control)) || - !(rx->flags & IEEE80211_RX_RA_MATCH)) { + !(status->rx_flags & IEEE80211_RX_RA_MATCH)) { /* Drop IBSS frames and frames for other hosts * silently. */ return RX_DROP_MONITOR; @@ -879,7 +880,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) * No point in finding a key and decrypting if the frame is neither * addressed to us nor a multicast frame. */ - if (!(rx->flags & IEEE80211_RX_RA_MATCH)) + if (!(status->rx_flags & IEEE80211_RX_RA_MATCH)) return RX_CONTINUE; /* start without a key */ @@ -1112,7 +1113,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) sta->last_rx = jiffies; } - if (!(rx->flags & IEEE80211_RX_RA_MATCH)) + if (!(status->rx_flags & IEEE80211_RX_RA_MATCH)) return RX_CONTINUE; if (rx->sdata->vif.type == NL80211_IFTYPE_STATION) @@ -1269,6 +1270,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) unsigned int frag, seq; struct ieee80211_fragment_entry *entry; struct sk_buff *skb; + struct ieee80211_rx_status *status; hdr = (struct ieee80211_hdr *)rx->skb->data; fc = hdr->frame_control; @@ -1368,7 +1370,8 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) } /* Complete frame has been reassembled - process it now */ - rx->flags |= IEEE80211_RX_FRAGMENTED; + status = IEEE80211_SKB_RXCB(rx->skb); + status->rx_flags |= IEEE80211_RX_FRAGMENTED; out: if (rx->sta) @@ -1385,9 +1388,10 @@ ieee80211_rx_h_ps_poll(struct ieee80211_rx_data *rx) { struct ieee80211_sub_if_data *sdata = rx->sdata; __le16 fc = ((struct ieee80211_hdr *)rx->skb->data)->frame_control; + struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); if (likely(!rx->sta || !ieee80211_is_pspoll(fc) || - !(rx->flags & IEEE80211_RX_RA_MATCH))) + !(status->rx_flags & IEEE80211_RX_RA_MATCH))) return RX_CONTINUE; if ((sdata->vif.type != NL80211_IFTYPE_AP) && @@ -1548,6 +1552,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) struct sk_buff *skb, *xmit_skb; struct ethhdr *ehdr = (struct ethhdr *) rx->skb->data; struct sta_info *dsta; + struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); skb = rx->skb; xmit_skb = NULL; @@ -1555,7 +1560,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) if ((sdata->vif.type == NL80211_IFTYPE_AP || sdata->vif.type == NL80211_IFTYPE_AP_VLAN) && !(sdata->flags & IEEE80211_SDATA_DONT_BRIDGE_PACKETS) && - (rx->flags & IEEE80211_RX_RA_MATCH) && + (status->rx_flags & IEEE80211_RX_RA_MATCH) && (sdata->vif.type != NL80211_IFTYPE_AP_VLAN || !sdata->u.vlan.sta)) { if (is_multicast_ether_addr(ehdr->h_dest)) { /* @@ -1632,6 +1637,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx) struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; __le16 fc = hdr->frame_control; struct sk_buff_head frame_list; + struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); if (unlikely(!ieee80211_is_data(fc))) return RX_CONTINUE; @@ -1639,7 +1645,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx) if (unlikely(!ieee80211_is_data_present(fc))) return RX_DROP_MONITOR; - if (!(rx->flags & IEEE80211_RX_AMSDU)) + if (!(status->rx_flags & IEEE80211_RX_AMSDU)) return RX_CONTINUE; if (ieee80211_has_a4(hdr->frame_control) && @@ -1690,6 +1696,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) struct sk_buff *skb = rx->skb, *fwd_skb; struct ieee80211_local *local = rx->local; struct ieee80211_sub_if_data *sdata = rx->sdata; + struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); hdr = (struct ieee80211_hdr *) skb->data; hdrlen = ieee80211_hdrlen(hdr->frame_control); @@ -1735,7 +1742,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) mesh_hdr->ttl--; - if (rx->flags & IEEE80211_RX_RA_MATCH) { + if (status->rx_flags & IEEE80211_RX_RA_MATCH) { if (!mesh_hdr->ttl) IEEE80211_IFSTA_MESH_CTR_INC(&rx->sdata->u.mesh, dropped_frames_ttl); @@ -1945,6 +1952,7 @@ static ieee80211_rx_result debug_noinline ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx) { struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data; + struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); /* * From here on, look only at management frames. @@ -1957,7 +1965,7 @@ ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx) if (!ieee80211_is_mgmt(mgmt->frame_control)) return RX_DROP_MONITOR; - if (!(rx->flags & IEEE80211_RX_RA_MATCH)) + if (!(status->rx_flags & IEEE80211_RX_RA_MATCH)) return RX_DROP_MONITOR; if (ieee80211_drop_unencrypted_mgmt(rx)) @@ -1972,6 +1980,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) struct ieee80211_local *local = rx->local; struct ieee80211_sub_if_data *sdata = rx->sdata; struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data; + struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); int len = rx->skb->len; if (!ieee80211_is_action(mgmt->frame_control)) @@ -1984,7 +1993,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) if (!rx->sta && mgmt->u.action.category != WLAN_CATEGORY_PUBLIC) return RX_DROP_UNUSABLE; - if (!(rx->flags & IEEE80211_RX_RA_MATCH)) + if (!(status->rx_flags & IEEE80211_RX_RA_MATCH)) return RX_DROP_UNUSABLE; switch (mgmt->u.action.category) { @@ -2080,7 +2089,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) return RX_CONTINUE; invalid: - rx->flags |= IEEE80211_MALFORMED_ACTION_FRM; + status->rx_flags |= IEEE80211_RX_MALFORMED_ACTION_FRM; /* will return in the next handlers */ return RX_CONTINUE; @@ -2102,10 +2111,10 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) static ieee80211_rx_result debug_noinline ieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data *rx) { - struct ieee80211_rx_status *status; + struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); /* skip known-bad action frames and return them in the next handler */ - if (rx->flags & IEEE80211_MALFORMED_ACTION_FRM) + if (status->rx_flags & IEEE80211_RX_MALFORMED_ACTION_FRM) return RX_CONTINUE; /* @@ -2114,7 +2123,6 @@ ieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data *rx) * so userspace can register for those to know whether ones * it transmitted were processed or returned. */ - status = IEEE80211_SKB_RXCB(rx->skb); if (cfg80211_rx_mgmt(rx->sdata->dev, status->freq, rx->skb->data, rx->skb->len, @@ -2136,6 +2144,7 @@ ieee80211_rx_h_action_return(struct ieee80211_rx_data *rx) struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data; struct sk_buff *nskb; struct ieee80211_sub_if_data *sdata = rx->sdata; + struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); if (!ieee80211_is_action(mgmt->frame_control)) return RX_CONTINUE; @@ -2150,7 +2159,7 @@ ieee80211_rx_h_action_return(struct ieee80211_rx_data *rx) * registration mechanisms, but older ones still use cooked * monitor interfaces so push all frames there. */ - if (!(rx->flags & IEEE80211_MALFORMED_ACTION_FRM) && + if (!(status->rx_flags & IEEE80211_RX_MALFORMED_ACTION_FRM) && (sdata->vif.type == NL80211_IFTYPE_AP || sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) return RX_DROP_MONITOR; @@ -2284,8 +2293,13 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx, struct net_device *prev_dev = NULL; struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); - if (status->flag & RX_FLAG_INTERNAL_CMTR) + /* + * If cooked monitor has been processed already, then + * don't do it again. If not, set the flag. + */ + if (rx->flags & IEEE80211_RX_CMNTR) goto out_free_skb; + rx->flags |= IEEE80211_RX_CMNTR; if (skb_headroom(skb) < sizeof(*rthdr) && pskb_expand_head(skb, sizeof(*rthdr), 0, GFP_ATOMIC)) @@ -2341,12 +2355,8 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx, if (prev_dev) { skb->dev = prev_dev; netif_receive_skb(skb); - skb = NULL; - } else - goto out_free_skb; - - status->flag |= RX_FLAG_INTERNAL_CMTR; - return; + return; + } out_free_skb: dev_kfree_skb(skb); @@ -2407,6 +2417,7 @@ static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx, * same TID from the same station */ rx->skb = skb; + rx->flags = 0; CALL_RXH(ieee80211_rx_h_decrypt) CALL_RXH(ieee80211_rx_h_check_more_data) @@ -2477,7 +2488,12 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_rx_data *rx) void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid) { struct sk_buff_head frames; - struct ieee80211_rx_data rx = { }; + struct ieee80211_rx_data rx = { + .sta = sta, + .sdata = sta->sdata, + .local = sta->local, + .queue = tid, + }; struct tid_ampdu_rx *tid_agg_rx; tid_agg_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]); @@ -2486,13 +2502,6 @@ void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid) __skb_queue_head_init(&frames); - /* construct rx struct */ - rx.sta = sta; - rx.sdata = sta->sdata; - rx.local = sta->local; - rx.queue = tid; - rx.flags |= IEEE80211_RX_RA_MATCH; - spin_lock(&tid_agg_rx->reorder_lock); ieee80211_sta_reorder_release(&sta->local->hw, tid_agg_rx, &frames); spin_unlock(&tid_agg_rx->reorder_lock); @@ -2519,7 +2528,7 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx, compare_ether_addr(sdata->vif.addr, hdr->addr1) != 0) { if (!(sdata->dev->flags & IFF_PROMISC)) return 0; - rx->flags &= ~IEEE80211_RX_RA_MATCH; + status->rx_flags &= ~IEEE80211_RX_RA_MATCH; } break; case NL80211_IFTYPE_ADHOC: @@ -2529,15 +2538,15 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx, return 1; } else if (!ieee80211_bssid_match(bssid, sdata->u.ibss.bssid)) { - if (!(rx->flags & IEEE80211_RX_IN_SCAN)) + if (!(status->rx_flags & IEEE80211_RX_IN_SCAN)) return 0; - rx->flags &= ~IEEE80211_RX_RA_MATCH; + status->rx_flags &= ~IEEE80211_RX_RA_MATCH; } else if (!multicast && compare_ether_addr(sdata->vif.addr, hdr->addr1) != 0) { if (!(sdata->dev->flags & IFF_PROMISC)) return 0; - rx->flags &= ~IEEE80211_RX_RA_MATCH; + status->rx_flags &= ~IEEE80211_RX_RA_MATCH; } else if (!rx->sta) { int rate_idx; if (status->flag & RX_FLAG_HT) @@ -2555,7 +2564,7 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx, if (!(sdata->dev->flags & IFF_PROMISC)) return 0; - rx->flags &= ~IEEE80211_RX_RA_MATCH; + status->rx_flags &= ~IEEE80211_RX_RA_MATCH; } break; case NL80211_IFTYPE_AP_VLAN: @@ -2566,9 +2575,9 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx, return 0; } else if (!ieee80211_bssid_match(bssid, sdata->vif.addr)) { - if (!(rx->flags & IEEE80211_RX_IN_SCAN)) + if (!(status->rx_flags & IEEE80211_RX_IN_SCAN)) return 0; - rx->flags &= ~IEEE80211_RX_RA_MATCH; + status->rx_flags &= ~IEEE80211_RX_RA_MATCH; } break; case NL80211_IFTYPE_WDS: @@ -2602,14 +2611,14 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx, int prepares; rx->skb = skb; - rx->flags |= IEEE80211_RX_RA_MATCH; + status->rx_flags |= IEEE80211_RX_RA_MATCH; prepares = prepare_for_handlers(rx, hdr); if (!prepares) return false; if (status->flag & RX_FLAG_MMIC_ERROR) { - if (rx->flags & IEEE80211_RX_RA_MATCH) + if (status->rx_flags & IEEE80211_RX_RA_MATCH) ieee80211_rx_michael_mic_report(hdr, rx); return false; } @@ -2638,6 +2647,7 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx, static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, struct sk_buff *skb) { + struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_sub_if_data *sdata; struct ieee80211_hdr *hdr; @@ -2657,7 +2667,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, if (unlikely(test_bit(SCAN_HW_SCANNING, &local->scanning) || test_bit(SCAN_OFF_CHANNEL, &local->scanning))) - rx.flags |= IEEE80211_RX_IN_SCAN; + status->rx_flags |= IEEE80211_RX_IN_SCAN; if (ieee80211_is_mgmt(fc)) err = skb_linearize(skb); @@ -2808,6 +2818,8 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb) } } + status->rx_flags = 0; + /* * key references and virtual interfaces are protected using RCU * and this requires that we are in a read-side RCU section during diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 43882b36da55..bee230d8fd11 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -117,7 +117,7 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx) key = &rx->key->conf.key[key_offset]; michael_mic(key, hdr, data, data_len, mic); if (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0 || wpa_test) { - if (!(rx->flags & IEEE80211_RX_RA_MATCH)) + if (!(status->rx_flags & IEEE80211_RX_RA_MATCH)) return RX_DROP_UNUSABLE; mac80211_ev_michael_mic_failure(rx->sdata, rx->key->conf.keyidx, -- cgit v1.2.3 From e2b626248b0799bd14be40ce290c6681a8419512 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Fri, 24 Sep 2010 17:58:50 +0530 Subject: ath9k_htc: Fix TKIP disconnect failure with HTC drivers The following commit removed splitmic. But forgot to add ATH_CRYPT_CAP_MIC_COMBINED flag for HTC drivers which causes TKIP to fail. Author: Bruno Randolf Date: Wed Sep 8 16:04:54 2010 +0900 ath/ath9k: Replace common->splitmic with a flag Replace common->splitmic with ATH_CRYPT_CAP_MIC_COMBINED flag. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/htc_drv_init.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index 33850c952314..b100db2766cf 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -561,6 +561,9 @@ static void ath9k_init_crypto(struct ath9k_htc_priv *priv) common->keymax = ATH_KEYMAX; } + if (priv->ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA) + common->crypt_caps |= ATH_CRYPT_CAP_MIC_COMBINED; + /* * Reset the key cache since some parts do not * reset the contents on initial power up. -- cgit v1.2.3 From d99bf6e707444af4df294f54a679f679018d7ec3 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Mon, 27 Sep 2010 14:00:51 -0400 Subject: wl12xx: fix separate-object-folder builds Make this go away (happens when building with a separate object directory): Assembler messages: Fatal error: can't create drivers/net/wireless/wl12xx/.tmp_wl12xx_platform_data.o: No such file or directory drivers/net/wireless/wl12xx/wl12xx_platform_data.c: In function 'wl12xx_get_platform_data': drivers/net/wireless/wl12xx/wl12xx_platform_data.c:28: error: cannot open drivers/net/wireless/wl12xx/.tmp_wl12xx_platform_data.gcno drivers/net/wireless/wl12xx/wl12xx_platform_data.c:28: confused by earlier errors, bailing out Signed-off-by: John W. Linville Reported-by: Stephen Rothwell Cc: Signed-off-by: Ohad Ben-Cohen --- drivers/net/wireless/Makefile | 3 +-- drivers/net/wireless/wl12xx/Makefile | 3 +++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index 85af697574a6..a13a602edb13 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -50,7 +50,6 @@ obj-$(CONFIG_ATH_COMMON) += ath/ obj-$(CONFIG_MAC80211_HWSIM) += mac80211_hwsim.o obj-$(CONFIG_WL12XX) += wl12xx/ -# small builtin driver bit -obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wl12xx/wl12xx_platform_data.o +obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wl12xx/ obj-$(CONFIG_IWM) += iwmc3200wifi/ diff --git a/drivers/net/wireless/wl12xx/Makefile b/drivers/net/wireless/wl12xx/Makefile index 078b4398ac1f..0d334d6f86f4 100644 --- a/drivers/net/wireless/wl12xx/Makefile +++ b/drivers/net/wireless/wl12xx/Makefile @@ -16,3 +16,6 @@ wl1271-$(CONFIG_NL80211_TESTMODE) += wl1271_testmode.o obj-$(CONFIG_WL1271) += wl1271.o obj-$(CONFIG_WL1271_SPI) += wl1271_spi.o obj-$(CONFIG_WL1271_SDIO) += wl1271_sdio.o + +# small builtin driver bit +obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wl12xx_platform_data.o -- cgit v1.2.3 From e7ee762cf074b0fd8eec483d0cef8fdbf0d04b81 Mon Sep 17 00:00:00 2001 From: Florian Mickler Date: Fri, 24 Sep 2010 18:22:01 +0200 Subject: iwl3945: queue the right work if the scan needs to be aborted iwl3945's scan_completed calls into the mac80211 stack which triggers a warn on if there is no scan outstanding. This can be avoided by not calling scan_completed but abort_scan in iwl3945_request_scan in the done: branch of the function which is used as an error out. The done: branch seems to be an error-out branch, as, for example, if iwl_is_ready(priv) returns false the done: branch is executed. NOTE: I'm not familiar with the driver at all. I just quickly scanned as a reaction to https://bugzilla.kernel.org/show_bug.cgi?id=17722 the users of scan_completed in the iwl3945 driver and noted the odd discrepancy between the comment above this instance and the comment in mac80211 scan_completed function. Signed-off-by: Florian Mickler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-lib.c | 2 +- drivers/net/wireless/iwlwifi/iwl3945-base.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index 9dd9e64c2b0b..8fd00a6e5120 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -1411,7 +1411,7 @@ void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) clear_bit(STATUS_SCAN_HW, &priv->status); clear_bit(STATUS_SCANNING, &priv->status); /* inform mac80211 scan aborted */ - queue_work(priv->workqueue, &priv->scan_completed); + queue_work(priv->workqueue, &priv->abort_scan); } int iwlagn_manage_ibss_station(struct iwl_priv *priv, diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 59a308b02f95..d31661c1ce77 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -3018,7 +3018,7 @@ void iwl3945_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) clear_bit(STATUS_SCANNING, &priv->status); /* inform mac80211 scan aborted */ - queue_work(priv->workqueue, &priv->scan_completed); + queue_work(priv->workqueue, &priv->abort_scan); } static void iwl3945_bg_restart(struct work_struct *data) -- cgit v1.2.3 From 8d4780eb1ece4e8109b4f6b2e5e61f7fc593c3f4 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Fri, 24 Sep 2010 21:59:57 -0400 Subject: mac80211: fix offchannel assumption upon association Association is dealt with as an atomic offchannel operation, we do this because we don't know we are associated until we get the associatin response from the AP. When we do get the associatin response though we were never clearing the offchannel state. This has a few implications, we told drivers we were still offchannel, and the first configured TX power for the channel does not take into account any power constraints. For ath9k this meant ANI calibration would not start upon association, and we'd have to wait until the first bgscan to be triggered. There may be other issues this resolves but I'm too lazy to comb the code to check. Cc: stable@kernel.org Cc: Amod Bodas Cc: Vasanth Thiagarajan Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- net/mac80211/main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 7c8542627351..e24fa5be4264 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -110,7 +110,8 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) chan = scan_chan; channel_type = NL80211_CHAN_NO_HT; local->hw.conf.flags |= IEEE80211_CONF_OFFCHANNEL; - } else if (local->tmp_channel) { + } else if (local->tmp_channel && + local->oper_channel != local->tmp_channel) { chan = scan_chan = local->tmp_channel; channel_type = local->tmp_channel_type; local->hw.conf.flags |= IEEE80211_CONF_OFFCHANNEL; -- cgit v1.2.3 From 793e721d21fd7d2825e3b7e56ff5009ec6d052e9 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sun, 26 Sep 2010 21:28:51 +0200 Subject: carl9170: remove non-standard ba session teardown 802.11n-2009 demands in 11.2.1: " When a STA enters normal (non-APSD) PS mode, any downlink Block ACK agreement without an associated schedule is suspended for the duration of this PS mode." The operative word is "suspended" and not terminated. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/ath/carl9170/main.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index 43de9dfa5820..d28b4ff8d281 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -1453,9 +1453,6 @@ static void carl9170_op_sta_notify(struct ieee80211_hw *hw, while ((skb = __skb_dequeue(&tid_info->queue))) __skb_queue_tail(&free, skb); spin_unlock_bh(&tid_info->lock); - - ieee80211_stop_tx_ba_session(sta, - tid_info->tid); } rcu_read_unlock(); } -- cgit v1.2.3 From b4c85d459c3a2c539a2d5885b12372e404bafc6b Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sun, 26 Sep 2010 21:40:40 +0200 Subject: carl9170: angle brackets for wiki link "The convention seems to be angle brackets around URLS in Kconfig." -- Finn Thain (to update web addresses in the kernel) Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/ath/carl9170/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/carl9170/Kconfig b/drivers/net/wireless/ath/carl9170/Kconfig index c5d3a3f2e55b..2d1b821b440d 100644 --- a/drivers/net/wireless/ath/carl9170/Kconfig +++ b/drivers/net/wireless/ath/carl9170/Kconfig @@ -10,7 +10,7 @@ config CARL9170 but it needs a special firmware (carl9170-1.fw) to do that. The firmware can be downloaded from our wiki here: - http://wireless.kernel.org/en/users/Drivers/carl9170 + If you choose to build a module, it'll be called carl9170. -- cgit v1.2.3 From 042c53f6e84896701b67012ad525bc44ea6de25f Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sun, 26 Sep 2010 21:48:31 +0200 Subject: carl9170: remove lost-frame workaround This patch removes some cruft, which survived the RFC review phase. Originally, carl9170_tx_ampdu_queue erroneously dropped a lot of frames. As a result the ampdu scheduler bogged down quite frequently and the affected BA session timed out. However this bug has been fixed and the WA and its debugfs counter is no longer useful. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/ath/carl9170/carl9170.h | 1 - drivers/net/wireless/ath/carl9170/debug.c | 4 --- drivers/net/wireless/ath/carl9170/tx.c | 37 ++-------------------------- 3 files changed, 2 insertions(+), 40 deletions(-) diff --git a/drivers/net/wireless/ath/carl9170/carl9170.h b/drivers/net/wireless/ath/carl9170/carl9170.h index d7c5482d74ce..20f2a77e54d2 100644 --- a/drivers/net/wireless/ath/carl9170/carl9170.h +++ b/drivers/net/wireless/ath/carl9170/carl9170.h @@ -364,7 +364,6 @@ struct ar9170 { unsigned int tx_dropped; unsigned int tx_ack_failures; unsigned int tx_fcs_errors; - unsigned int tx_ampdu_timeout; unsigned int rx_dropped; /* EEPROM */ diff --git a/drivers/net/wireless/ath/carl9170/debug.c b/drivers/net/wireless/ath/carl9170/debug.c index 19b48369ffed..0ac1124c2a0b 100644 --- a/drivers/net/wireless/ath/carl9170/debug.c +++ b/drivers/net/wireless/ath/carl9170/debug.c @@ -798,8 +798,6 @@ DEBUGFS_READONLY_FILE(tx_total_queued, 20, "%d", atomic_read(&ar->tx_total_queued)); DEBUGFS_READONLY_FILE(tx_ampdu_scheduler, 20, "%d", atomic_read(&ar->tx_ampdu_scheduler)); -DEBUGFS_READONLY_FILE(tx_ampdu_timeout, 20, "%d", - ar->tx_ampdu_timeout); DEBUGFS_READONLY_FILE(tx_total_pending, 20, "%d", atomic_read(&ar->tx_total_pending)); @@ -872,8 +870,6 @@ void carl9170_debugfs_register(struct ar9170 *ar) DEBUGFS_ADD(ampdu_density); DEBUGFS_ADD(ampdu_factor); - DEBUGFS_ADD(tx_ampdu_timeout); - DEBUGFS_ADD(tx_janitor_last_run); DEBUGFS_ADD(tx_status_0); diff --git a/drivers/net/wireless/ath/carl9170/tx.c b/drivers/net/wireless/ath/carl9170/tx.c index e0d2374e0c77..e6be5e6c1723 100644 --- a/drivers/net/wireless/ath/carl9170/tx.c +++ b/drivers/net/wireless/ath/carl9170/tx.c @@ -1042,41 +1042,8 @@ retry: queue = TID_TO_WME_AC(tid_info->tid); spin_lock_bh(&tid_info->lock); - if (tid_info->state != CARL9170_TID_STATE_XMIT) { - first = skb_peek(&tid_info->queue); - if (first) { - struct ieee80211_tx_info *txinfo; - struct carl9170_tx_info *arinfo; - - txinfo = IEEE80211_SKB_CB(first); - arinfo = (void *) txinfo->rate_driver_data; - - if (time_is_after_jiffies(arinfo->timeout + - msecs_to_jiffies(CARL9170_QUEUE_TIMEOUT)) - == true) - goto processed; - - /* - * We've been waiting for the frame which - * matches "snx" (start sequence of the - * next aggregate) for some time now. - * - * But it never arrived. Therefore - * jump to the next available frame - * and kick-start the transmission. - * - * Note: This might induce odd latency - * spikes because the receiver will be - * waiting for the lost frame too. - */ - ar->tx_ampdu_timeout++; - - tid_info->snx = carl9170_get_seq(first); - tid_info->state = CARL9170_TID_STATE_XMIT; - } else { - goto processed; - } - } + if (tid_info->state != CARL9170_TID_STATE_XMIT) + goto processed; tid_info->counter++; first = skb_peek(&tid_info->queue); -- cgit v1.2.3 From cb139ecc0c030e8ccc736bd86cfef502c200825a Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sun, 26 Sep 2010 22:49:34 +0200 Subject: carl9170: fix tx_ampdu_upload counter tx_ampdu_upload was not decreased when an a-MPDU frame had to be kicked out from the tx_pending queues. This broke ampdu aggregation, because the scheduler waits until tx_ampdu_upload drops to zero, before making the next aggregate. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/ath/carl9170/main.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index d28b4ff8d281..a8b0cec78b32 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -230,8 +230,15 @@ static void carl9170_flush(struct ar9170 *ar, bool drop_queued) for (i = 0; i < ar->hw->queues; i++) { struct sk_buff *skb; - while ((skb = skb_dequeue(&ar->tx_pending[i]))) + while ((skb = skb_dequeue(&ar->tx_pending[i]))) { + struct ieee80211_tx_info *info; + + info = IEEE80211_SKB_CB(skb); + if (info->flags & IEEE80211_TX_CTL_AMPDU) + atomic_dec(&ar->tx_ampdu_upload); + carl9170_tx_status(ar, skb, false); + } } } @@ -1462,6 +1469,7 @@ static void carl9170_op_sta_notify(struct ieee80211_hw *hw, skb_queue_walk_safe(&ar->tx_pending[i], skb, tmp) { struct _carl9170_tx_superframe *super; struct ieee80211_hdr *hdr; + struct ieee80211_tx_info *info; super = (void *) skb->data; hdr = (void *) super->frame_data; @@ -1470,6 +1478,11 @@ static void carl9170_op_sta_notify(struct ieee80211_hw *hw, continue; __skb_unlink(skb, &ar->tx_pending[i]); + + info = IEEE80211_SKB_CB(skb); + if (info->flags & IEEE80211_TX_CTL_AMPDU) + atomic_dec(&ar->tx_ampdu_upload); + carl9170_tx_status(ar, skb, false); } spin_unlock_bh(&ar->tx_pending[i].lock); -- cgit v1.2.3 From 9c655c8be9053a65886ac3e06420399a9bfdbd70 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sun, 26 Sep 2010 23:06:56 +0200 Subject: carl9170: fix WARN_ON triggered by Broadcom HT STAs Broadcom's Windows driver for the 4313 advertises an ampdu density of 7 => 16 us. The AR9170 MAC on the other hand only supports densities up to 8 us. This patch removes the noisy WARN_ON, because there is nothing we can do about it. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/ath/carl9170/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index a8b0cec78b32..84bd38e9961c 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -1248,7 +1248,7 @@ static int carl9170_op_ampdu_action(struct ieee80211_hw *hw, switch (action) { case IEEE80211_AMPDU_TX_START: - if (WARN_ON_ONCE(!sta_info->ht_sta)) + if (!sta_info->ht_sta) return -EOPNOTSUPP; rcu_read_lock(); -- cgit v1.2.3 From 4bd437ea40b81fb4c047034de6dca1b5af496fb0 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Mon, 27 Sep 2010 01:36:38 +0200 Subject: carl9170: revamp carl9170_tx_prepare David Miller complained about the driver's excessive use of variables in __packed structs. While I did not fully agree with his sole "performance" argument on all accounts. I do see some room for improvement in hot-paths on architectures without an efficient access to unaligned elements. This first patch (dare I say?) optimizes an important tx hot-path in the driver: carl9170_tx_prepare. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/ath/carl9170/tx.c | 155 ++++++++++++++++----------------- 1 file changed, 75 insertions(+), 80 deletions(-) diff --git a/drivers/net/wireless/ath/carl9170/tx.c b/drivers/net/wireless/ath/carl9170/tx.c index e6be5e6c1723..b575c865142d 100644 --- a/drivers/net/wireless/ath/carl9170/tx.c +++ b/drivers/net/wireless/ath/carl9170/tx.c @@ -760,8 +760,8 @@ static int carl9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb) struct carl9170_tx_info *arinfo; unsigned int hw_queue; int i; - u16 keytype = 0; - u16 len, icv = 0; + __le16 mac_tmp; + u16 len; bool ampdu, no_ack; BUILD_BUG_ON(sizeof(*arinfo) > sizeof(info->rate_driver_data)); @@ -773,6 +773,10 @@ static int carl9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb) BUILD_BUG_ON(IEEE80211_TX_MAX_RATES < CARL9170_TX_MAX_RATES); + BUILD_BUG_ON(AR9170_MAX_VIRTUAL_MAC > + ((CARL9170_TX_SUPER_MISC_VIF_ID >> + CARL9170_TX_SUPER_MISC_VIF_ID_S) + 1)); + hw_queue = ar9170_qmap[carl9170_get_queue(ar, skb)]; hdr = (void *)skb->data; @@ -793,20 +797,37 @@ static int carl9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb) txc = (void *)skb_push(skb, sizeof(*txc)); memset(txc, 0, sizeof(*txc)); - ampdu = !!(info->flags & IEEE80211_TX_CTL_AMPDU); + SET_VAL(CARL9170_TX_SUPER_MISC_QUEUE, txc->s.misc, hw_queue); + + if (likely(cvif)) + SET_VAL(CARL9170_TX_SUPER_MISC_VIF_ID, txc->s.misc, cvif->id); + + if (unlikely(info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM)) + txc->s.misc |= CARL9170_TX_SUPER_MISC_CAB; + + if (unlikely(ieee80211_is_probe_resp(hdr->frame_control))) + txc->s.misc |= CARL9170_TX_SUPER_MISC_FILL_IN_TSF; + + mac_tmp = cpu_to_le16(AR9170_TX_MAC_HW_DURATION | + AR9170_TX_MAC_BACKOFF); + mac_tmp |= cpu_to_le16((hw_queue << AR9170_TX_MAC_QOS_S) && + AR9170_TX_MAC_QOS); + no_ack = !!(info->flags & IEEE80211_TX_CTL_NO_ACK); + if (unlikely(no_ack)) + mac_tmp |= cpu_to_le16(AR9170_TX_MAC_NO_ACK); if (info->control.hw_key) { - icv = info->control.hw_key->icv_len; + len += info->control.hw_key->icv_len; switch (info->control.hw_key->cipher) { case WLAN_CIPHER_SUITE_WEP40: case WLAN_CIPHER_SUITE_WEP104: case WLAN_CIPHER_SUITE_TKIP: - keytype = AR9170_TX_MAC_ENCR_RC4; + mac_tmp |= cpu_to_le16(AR9170_TX_MAC_ENCR_RC4); break; case WLAN_CIPHER_SUITE_CCMP: - keytype = AR9170_TX_MAC_ENCR_AES; + mac_tmp |= cpu_to_le16(AR9170_TX_MAC_ENCR_AES); break; default: WARN_ON(1); @@ -814,48 +835,58 @@ static int carl9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb) } } - BUILD_BUG_ON(AR9170_MAX_VIRTUAL_MAC > - ((CARL9170_TX_SUPER_MISC_VIF_ID >> - CARL9170_TX_SUPER_MISC_VIF_ID_S) + 1)); - - txc->s.len = cpu_to_le16(len + sizeof(*txc)); - txc->f.length = cpu_to_le16(len + icv + 4); - SET_VAL(CARL9170_TX_SUPER_MISC_VIF_ID, txc->s.misc, - cvif ? cvif->id : 0); + ampdu = !!(info->flags & IEEE80211_TX_CTL_AMPDU); + if (ampdu) { + unsigned int density, factor; - txc->f.mac_control = cpu_to_le16(AR9170_TX_MAC_HW_DURATION | - AR9170_TX_MAC_BACKOFF); + if (unlikely(!sta || !cvif)) + goto err_out; - SET_VAL(CARL9170_TX_SUPER_MISC_QUEUE, txc->s.misc, hw_queue); + factor = min_t(unsigned int, 1u, + info->control.sta->ht_cap.ampdu_factor); - txc->f.mac_control |= cpu_to_le16(hw_queue << AR9170_TX_MAC_QOS_S); - txc->f.mac_control |= cpu_to_le16(keytype); - txc->f.phy_control = cpu_to_le32(0); + density = info->control.sta->ht_cap.ampdu_density; - if (no_ack) - txc->f.mac_control |= cpu_to_le16(AR9170_TX_MAC_NO_ACK); + if (density) { + /* + * Watch out! + * + * Otus uses slightly different density values than + * those from the 802.11n spec. + */ - if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) - txc->s.misc |= CARL9170_TX_SUPER_MISC_CAB; + density = max_t(unsigned int, density + 1, 7u); + } - txrate = &info->control.rates[0]; - if (carl9170_tx_rts_check(ar, txrate, ampdu, no_ack)) - txc->f.mac_control |= cpu_to_le16(AR9170_TX_MAC_PROT_RTS); - else if (carl9170_tx_cts_check(ar, txrate)) - txc->f.mac_control |= cpu_to_le16(AR9170_TX_MAC_PROT_CTS); + SET_VAL(CARL9170_TX_SUPER_AMPDU_DENSITY, + txc->s.ampdu_settings, density); - SET_VAL(CARL9170_TX_SUPER_RI_TRIES, txc->s.ri[0], txrate->count); - txc->f.phy_control |= carl9170_tx_physet(ar, info, txrate); + SET_VAL(CARL9170_TX_SUPER_AMPDU_FACTOR, + txc->s.ampdu_settings, factor); - if (info->flags & IEEE80211_TX_CTL_AMPDU) { - for (i = 1; i < CARL9170_TX_MAX_RATES; i++) { + for (i = 0; i < CARL9170_TX_MAX_RATES; i++) { txrate = &info->control.rates[i]; - if (txrate->idx >= 0) + if (txrate->idx >= 0) { + txc->s.ri[i] = + CARL9170_TX_SUPER_RI_AMPDU; + + if (WARN_ON(!(txrate->flags & + IEEE80211_TX_RC_MCS))) { + /* + * Not sure if it's even possible + * to aggregate non-ht rates with + * this HW. + */ + goto err_out; + } continue; + } txrate->idx = 0; txrate->count = ar->hw->max_rate_tries; } + + mac_tmp |= cpu_to_le16(AR9170_TX_MAC_AGGR); } /* @@ -878,57 +909,21 @@ static int carl9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb) txc->s.ri[i] |= (AR9170_TX_MAC_PROT_CTS << CARL9170_TX_SUPER_RI_ERP_PROT_S); - /* - * unaggregated fallback, in case aggregation - * proves to be unsuccessful and unreliable. - */ - if (ampdu && i < 3) - txc->s.ri[i] |= CARL9170_TX_SUPER_RI_AMPDU; - txc->s.rr[i - 1] = carl9170_tx_physet(ar, info, txrate); } - if (ieee80211_is_probe_resp(hdr->frame_control)) - txc->s.misc |= CARL9170_TX_SUPER_MISC_FILL_IN_TSF; - - if (ampdu) { - unsigned int density, factor; - - if (unlikely(!sta || !cvif)) - goto err_out; - - density = info->control.sta->ht_cap.ampdu_density; - factor = info->control.sta->ht_cap.ampdu_factor; - - if (density) { - /* - * Watch out! - * - * Otus uses slightly different density values than - * those from the 802.11n spec. - */ - - density = max_t(unsigned int, density + 1, 7u); - } - - factor = min_t(unsigned int, 1u, factor); - - SET_VAL(CARL9170_TX_SUPER_AMPDU_DENSITY, - txc->s.ampdu_settings, density); + txrate = &info->control.rates[0]; + SET_VAL(CARL9170_TX_SUPER_RI_TRIES, txc->s.ri[0], txrate->count); - SET_VAL(CARL9170_TX_SUPER_AMPDU_FACTOR, - txc->s.ampdu_settings, factor); + if (carl9170_tx_rts_check(ar, txrate, ampdu, no_ack)) + mac_tmp |= cpu_to_le16(AR9170_TX_MAC_PROT_RTS); + else if (carl9170_tx_cts_check(ar, txrate)) + mac_tmp |= cpu_to_le16(AR9170_TX_MAC_PROT_CTS); - if (info->control.rates[0].flags & IEEE80211_TX_RC_MCS) { - txc->f.mac_control |= cpu_to_le16(AR9170_TX_MAC_AGGR); - } else { - /* - * Not sure if it's even possible to aggregate - * non-ht rates with this HW. - */ - WARN_ON_ONCE(1); - } - } + txc->s.len = cpu_to_le16(skb->len); + txc->f.length = cpu_to_le16(len + FCS_LEN); + txc->f.mac_control = mac_tmp; + txc->f.phy_control = carl9170_tx_physet(ar, info, txrate); arinfo = (void *)info->rate_driver_data; arinfo->timeout = jiffies; -- cgit v1.2.3 From 4a79f2c517cce31c3b25aab0ec5078368b22c363 Mon Sep 17 00:00:00 2001 From: Bruno Randolf Date: Mon, 27 Sep 2010 12:22:16 +0900 Subject: ath5k: Remove unused variable for atim window It's not used and it's unlikely we will ever implement ATIM. Signed-off-by: Bruno Randolf Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/ath5k.h | 1 - drivers/net/wireless/ath/ath5k/attach.c | 1 - drivers/net/wireless/ath/ath5k/pcu.c | 2 +- 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index b96bb985b56d..42e6e821259e 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -1041,7 +1041,6 @@ struct ath5k_hw { #define ah_modes ah_capabilities.cap_mode #define ah_ee_version ah_capabilities.cap_eeprom.ee_version - u32 ah_atim_window; u32 ah_limit_tx_retries; u8 ah_coverage_class; diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c index 6e02de311cdd..cd0b14a0a93a 100644 --- a/drivers/net/wireless/ath/ath5k/attach.c +++ b/drivers/net/wireless/ath/ath5k/attach.c @@ -118,7 +118,6 @@ int ath5k_hw_attach(struct ath5k_softc *sc) ah->ah_turbo = false; ah->ah_txpower.txp_tpc = AR5K_TUNE_TPC_TXPOWER; ah->ah_imr = 0; - ah->ah_atim_window = 0; ah->ah_limit_tx_retries = AR5K_INIT_TX_RETRY; ah->ah_software_retry = false; ah->ah_ant_mode = AR5K_ANTMODE_DEFAULT; diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c index 6a891c4484a0..71dca1023e72 100644 --- a/drivers/net/wireless/ath/ath5k/pcu.c +++ b/drivers/net/wireless/ath/ath5k/pcu.c @@ -600,7 +600,7 @@ void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval) /* Timer3 marks the end of our ATIM window * a zero length window is not allowed because * we 'll get no beacons */ - timer3 = next_beacon + (ah->ah_atim_window ? ah->ah_atim_window : 1); + timer3 = next_beacon + 1; /* * Set the beacon register and enable all timers. -- cgit v1.2.3 From 7f896126017830b29cf501d246ee32b81e359acd Mon Sep 17 00:00:00 2001 From: Bruno Randolf Date: Mon, 27 Sep 2010 12:22:21 +0900 Subject: ath5k: Check and fix ATIM window This patch adds sanity-checks for the beacon timers and especially the ATIM window to ath5k. It is basically the same what i did for madwifi two years ago and fixes a problem in IBSS mode which has been described as "ramping" pings. See the code comments for a more detailed description and these links: http://madwifi-project.org/ticket/1154 http://madwifi-project.org/changeset/3867 http://thread.gmane.org/gmane.linux.drivers.madwifi.devel/6066 Signed-off-by: Bruno Randolf Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/ath5k.h | 1 + drivers/net/wireless/ath/ath5k/base.c | 9 ++++ drivers/net/wireless/ath/ath5k/pcu.c | 91 ++++++++++++++++++++++++++++++++++ 3 files changed, 101 insertions(+) diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 42e6e821259e..0cba2e315d9a 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -1195,6 +1195,7 @@ u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah); void ath5k_hw_set_tsf64(struct ath5k_hw *ah, u64 tsf64); void ath5k_hw_reset_tsf(struct ath5k_hw *ah); void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval); +bool ath5k_hw_check_beacon_timers(struct ath5k_hw *ah, int intval); /* ACK bit rate */ void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, bool high); /* Clock rate related functions */ diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 95072db0ec21..4103765000ea 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -1191,6 +1191,15 @@ ath5k_check_ibss_tsf(struct ath5k_softc *sc, struct sk_buff *skb, */ if (hw_tu >= sc->nexttbtt) ath5k_beacon_update_timers(sc, bc_tstamp); + + /* Check if the beacon timers are still correct, because a TSF + * update might have created a window between them - for a + * longer description see the comment of this function: */ + if (!ath5k_hw_check_beacon_timers(sc->ah, sc->bintval)) { + ath5k_beacon_update_timers(sc, bc_tstamp); + ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, + "fixed beacon timers after beacon receive\n"); + } } } diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c index 71dca1023e72..604114fb34b1 100644 --- a/drivers/net/wireless/ath/ath5k/pcu.c +++ b/drivers/net/wireless/ath/ath5k/pcu.c @@ -640,6 +640,97 @@ void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval) } +/** + * ath5k_check_timer_win - Check if timer B is timer A + window + * + * @a: timer a (before b) + * @b: timer b (after a) + * @window: difference between a and b + * @intval: timers are increased by this interval + * + * This helper function checks if timer B is timer A + window and covers + * cases where timer A or B might have already been updated or wrapped + * around (Timers are 16 bit). + * + * Returns true if O.K. + */ +static inline bool +ath5k_check_timer_win(int a, int b, int window, int intval) +{ + /* + * 1.) usually B should be A + window + * 2.) A already updated, B not updated yet + * 3.) A already updated and has wrapped around + * 4.) B has wrapped around + */ + if ((b - a == window) || /* 1.) */ + (a - b == intval - window) || /* 2.) */ + ((a | 0x10000) - b == intval - window) || /* 3.) */ + ((b | 0x10000) - a == window)) /* 4.) */ + return true; /* O.K. */ + return false; +} + +/** + * ath5k_hw_check_beacon_timers - Check if the beacon timers are correct + * + * @ah: The &struct ath5k_hw + * @intval: beacon interval + * + * This is a workaround for IBSS mode: + * + * The need for this function arises from the fact that we have 4 separate + * HW timer registers (TIMER0 - TIMER3), which are closely related to the + * next beacon target time (NBTT), and that the HW updates these timers + * seperately based on the current TSF value. The hardware increments each + * timer by the beacon interval, when the local TSF coverted to TU is equal + * to the value stored in the timer. + * + * The reception of a beacon with the same BSSID can update the local HW TSF + * at any time - this is something we can't avoid. If the TSF jumps to a + * time which is later than the time stored in a timer, this timer will not + * be updated until the TSF in TU wraps around at 16 bit (the size of the + * timers) and reaches the time which is stored in the timer. + * + * The problem is that these timers are closely related to TIMER0 (NBTT) and + * that they define a time "window". When the TSF jumps between two timers + * (e.g. ATIM and NBTT), the one in the past will be left behind (not + * updated), while the one in the future will be updated every beacon + * interval. This causes the window to get larger, until the TSF wraps + * around as described above and the timer which was left behind gets + * updated again. But - because the beacon interval is usually not an exact + * divisor of the size of the timers (16 bit), an unwanted "window" between + * these timers has developed! + * + * This is especially important with the ATIM window, because during + * the ATIM window only ATIM frames and no data frames are allowed to be + * sent, which creates transmission pauses after each beacon. This symptom + * has been described as "ramping ping" because ping times increase linearly + * for some time and then drop down again. A wrong window on the DMA beacon + * timer has the same effect, so we check for these two conditions. + * + * Returns true if O.K. + */ +bool +ath5k_hw_check_beacon_timers(struct ath5k_hw *ah, int intval) +{ + unsigned int nbtt, atim, dma; + + nbtt = ath5k_hw_reg_read(ah, AR5K_TIMER0); + atim = ath5k_hw_reg_read(ah, AR5K_TIMER3); + dma = ath5k_hw_reg_read(ah, AR5K_TIMER1) >> 3; + + /* NOTE: SWBA is different. Having a wrong window there does not + * stop us from sending data and this condition is catched thru + * other means (SWBA interrupt) */ + + if (ath5k_check_timer_win(nbtt, atim, 1, intval) && + ath5k_check_timer_win(dma, nbtt, AR5K_TUNE_DMA_BEACON_RESP, + intval)) + return true; /* O.K. */ + return false; +} + /** * ath5k_hw_set_coverage_class - Set IEEE 802.11 coverage class * -- cgit v1.2.3 From 11f21df36cbcffbfada9307e809d4372ece27f47 Mon Sep 17 00:00:00 2001 From: Bruno Randolf Date: Mon, 27 Sep 2010 12:22:26 +0900 Subject: ath5k: Increase "fudge" for beacon timers We use FUDGE to make sure the next TBTT is ahead of the current TU. Since we later substract AR5K_TUNE_SW_BEACON_RESP (10) in the timer configuration we need to make sure it is bigger than that. Signed-off-by: Bruno Randolf Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/base.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 4103765000ea..94cc3354f3a6 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -1886,8 +1886,11 @@ ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf) hw_tsf = ath5k_hw_get_tsf64(ah); hw_tu = TSF_TO_TU(hw_tsf); -#define FUDGE 3 - /* we use FUDGE to make sure the next TBTT is ahead of the current TU */ +#define FUDGE AR5K_TUNE_SW_BEACON_RESP + 3 + /* We use FUDGE to make sure the next TBTT is ahead of the current TU. + * Since we later substract AR5K_TUNE_SW_BEACON_RESP (10) in the timer + * configuration we need to make sure it is bigger than that. */ + if (bc_tsf == -1) { /* * no beacons received, called internally. -- cgit v1.2.3 From 28df897a42aa41d6318be5b9872c4bb5c8d8d7e3 Mon Sep 17 00:00:00 2001 From: Bruno Randolf Date: Mon, 27 Sep 2010 12:22:32 +0900 Subject: ath5k: Disable interrupts in ath5k_hw_get_tsf64 The code in ath5k_hw_get_tsf64() is time critical and will return wrong results if we get interrupted, so disable local interrupts. Signed-off-by: Bruno Randolf Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/pcu.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c index 604114fb34b1..095d30b50ec7 100644 --- a/drivers/net/wireless/ath/ath5k/pcu.c +++ b/drivers/net/wireless/ath/ath5k/pcu.c @@ -495,6 +495,10 @@ u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah) { u32 tsf_lower, tsf_upper1, tsf_upper2; int i; + unsigned long flags; + + /* This code is time critical - we don't want to be interrupted here */ + local_irq_save(flags); /* * While reading TSF upper and then lower part, the clock is still @@ -517,6 +521,8 @@ u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah) tsf_upper1 = tsf_upper2; } + local_irq_restore(flags); + WARN_ON( i == ATH5K_MAX_TSF_READ ); return (((u64)tsf_upper1 << 32) | tsf_lower); -- cgit v1.2.3 From eada7cad6005006b457f10a4c3e1881ff99d03a4 Mon Sep 17 00:00:00 2001 From: Bruno Randolf Date: Mon, 27 Sep 2010 13:02:40 +0900 Subject: ath5k: Fix bitmasks and typos for PCU Diagnostic register As reported by Ryan Niemi, some bitmasks in the register definition for the PCU Diagnostic register (DIAG_SW) were missing a zero at the end. While at it fix some typos and add more comments. Signed-off-by: Bruno Randolf Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/dma.c | 4 ++-- drivers/net/wireless/ath/ath5k/phy.c | 4 ++-- drivers/net/wireless/ath/ath5k/reg.h | 29 ++++++++++++++--------------- 3 files changed, 18 insertions(+), 19 deletions(-) diff --git a/drivers/net/wireless/ath/ath5k/dma.c b/drivers/net/wireless/ath/ath5k/dma.c index 58bb6c5dda7b..923c9ca5c4f0 100644 --- a/drivers/net/wireless/ath/ath5k/dma.c +++ b/drivers/net/wireless/ath/ath5k/dma.c @@ -244,7 +244,7 @@ int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue) /* Force channel idle high */ AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW_5211, - AR5K_DIAG_SW_CHANEL_IDLE_HIGH); + AR5K_DIAG_SW_CHANNEL_IDLE_HIGH); /* Wait a while and disable mechanism */ udelay(200); @@ -261,7 +261,7 @@ int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue) } while (--i && pending); AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW_5211, - AR5K_DIAG_SW_CHANEL_IDLE_HIGH); + AR5K_DIAG_SW_CHANNEL_IDLE_HIGH); } /* Clear register */ diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index 4932bf2f35eb..61da913e7c8f 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c @@ -1257,7 +1257,7 @@ static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah, * Disable beacons and RX/TX queues, wait */ AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW_5210, - AR5K_DIAG_SW_DIS_TX | AR5K_DIAG_SW_DIS_RX_5210); + AR5K_DIAG_SW_DIS_TX_5210 | AR5K_DIAG_SW_DIS_RX_5210); beacon = ath5k_hw_reg_read(ah, AR5K_BEACON_5210); ath5k_hw_reg_write(ah, beacon & ~AR5K_BEACON_ENABLE, AR5K_BEACON_5210); @@ -1336,7 +1336,7 @@ static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah, * Re-enable RX/TX and beacons */ AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW_5210, - AR5K_DIAG_SW_DIS_TX | AR5K_DIAG_SW_DIS_RX_5210); + AR5K_DIAG_SW_DIS_TX_5210 | AR5K_DIAG_SW_DIS_RX_5210); ath5k_hw_reg_write(ah, beacon, AR5K_BEACON_5210); return 0; diff --git a/drivers/net/wireless/ath/ath5k/reg.h b/drivers/net/wireless/ath/ath5k/reg.h index 67d63081705a..a34929f06533 100644 --- a/drivers/net/wireless/ath/ath5k/reg.h +++ b/drivers/net/wireless/ath/ath5k/reg.h @@ -1387,10 +1387,9 @@ /* - * PCU control register + * PCU Diagnostic register * - * Only DIS_RX is used in the code, the rest i guess are - * for tweaking/diagnostics. + * Used for tweaking/diagnostics. */ #define AR5K_DIAG_SW_5210 0x8068 /* Register Address [5210] */ #define AR5K_DIAG_SW_5211 0x8048 /* Register Address [5211+] */ @@ -1399,22 +1398,22 @@ #define AR5K_DIAG_SW_DIS_WEP_ACK 0x00000001 /* Disable ACKs if WEP key is invalid */ #define AR5K_DIAG_SW_DIS_ACK 0x00000002 /* Disable ACKs */ #define AR5K_DIAG_SW_DIS_CTS 0x00000004 /* Disable CTSs */ -#define AR5K_DIAG_SW_DIS_ENC 0x00000008 /* Disable encryption */ -#define AR5K_DIAG_SW_DIS_DEC 0x00000010 /* Disable decryption */ -#define AR5K_DIAG_SW_DIS_TX 0x00000020 /* Disable transmit [5210] */ -#define AR5K_DIAG_SW_DIS_RX_5210 0x00000040 /* Disable recieve */ +#define AR5K_DIAG_SW_DIS_ENC 0x00000008 /* Disable HW encryption */ +#define AR5K_DIAG_SW_DIS_DEC 0x00000010 /* Disable HW decryption */ +#define AR5K_DIAG_SW_DIS_TX_5210 0x00000020 /* Disable transmit [5210] */ +#define AR5K_DIAG_SW_DIS_RX_5210 0x00000040 /* Disable receive */ #define AR5K_DIAG_SW_DIS_RX_5211 0x00000020 #define AR5K_DIAG_SW_DIS_RX (ah->ah_version == AR5K_AR5210 ? \ AR5K_DIAG_SW_DIS_RX_5210 : AR5K_DIAG_SW_DIS_RX_5211) -#define AR5K_DIAG_SW_LOOP_BACK_5210 0x00000080 /* Loopback (i guess it goes with DIS_TX) [5210] */ +#define AR5K_DIAG_SW_LOOP_BACK_5210 0x00000080 /* TX Data Loopback (i guess it goes with DIS_TX) [5210] */ #define AR5K_DIAG_SW_LOOP_BACK_5211 0x00000040 #define AR5K_DIAG_SW_LOOP_BACK (ah->ah_version == AR5K_AR5210 ? \ AR5K_DIAG_SW_LOOP_BACK_5210 : AR5K_DIAG_SW_LOOP_BACK_5211) -#define AR5K_DIAG_SW_CORR_FCS_5210 0x00000100 /* Corrupted FCS */ +#define AR5K_DIAG_SW_CORR_FCS_5210 0x00000100 /* Generate invalid TX FCS */ #define AR5K_DIAG_SW_CORR_FCS_5211 0x00000080 #define AR5K_DIAG_SW_CORR_FCS (ah->ah_version == AR5K_AR5210 ? \ AR5K_DIAG_SW_CORR_FCS_5210 : AR5K_DIAG_SW_CORR_FCS_5211) -#define AR5K_DIAG_SW_CHAN_INFO_5210 0x00000200 /* Dump channel info */ +#define AR5K_DIAG_SW_CHAN_INFO_5210 0x00000200 /* Add 56 bytes of channel info before the frame data in the RX buffer */ #define AR5K_DIAG_SW_CHAN_INFO_5211 0x00000100 #define AR5K_DIAG_SW_CHAN_INFO (ah->ah_version == AR5K_AR5210 ? \ AR5K_DIAG_SW_CHAN_INFO_5210 : AR5K_DIAG_SW_CHAN_INFO_5211) @@ -1426,17 +1425,17 @@ #define AR5K_DIAG_SW_SCVRAM_SEED 0x0003f800 /* [5210] */ #define AR5K_DIAG_SW_SCRAM_SEED_M 0x0001fc00 /* Scrambler seed mask */ #define AR5K_DIAG_SW_SCRAM_SEED_S 10 -#define AR5K_DIAG_SW_DIS_SEQ_INC 0x00040000 /* Disable seqnum increment (?)[5210] */ +#define AR5K_DIAG_SW_DIS_SEQ_INC_5210 0x00040000 /* Disable seqnum increment (?)[5210] */ #define AR5K_DIAG_SW_FRAME_NV0_5210 0x00080000 #define AR5K_DIAG_SW_FRAME_NV0_5211 0x00020000 /* Accept frames of non-zero protocol number */ #define AR5K_DIAG_SW_FRAME_NV0 (ah->ah_version == AR5K_AR5210 ? \ AR5K_DIAG_SW_FRAME_NV0_5210 : AR5K_DIAG_SW_FRAME_NV0_5211) #define AR5K_DIAG_SW_OBSPT_M 0x000c0000 /* Observation point select (?) */ #define AR5K_DIAG_SW_OBSPT_S 18 -#define AR5K_DIAG_SW_RX_CLEAR_HIGH 0x0010000 /* Force RX Clear high */ -#define AR5K_DIAG_SW_IGNORE_CARR_SENSE 0x0020000 /* Ignore virtual carrier sense */ -#define AR5K_DIAG_SW_CHANEL_IDLE_HIGH 0x0040000 /* Force channel idle high */ -#define AR5K_DIAG_SW_PHEAR_ME 0x0080000 /* ??? */ +#define AR5K_DIAG_SW_RX_CLEAR_HIGH 0x00100000 /* Ignore carrier sense */ +#define AR5K_DIAG_SW_IGNORE_CARR_SENSE 0x00200000 /* Ignore virtual carrier sense */ +#define AR5K_DIAG_SW_CHANNEL_IDLE_HIGH 0x00400000 /* Force channel idle high */ +#define AR5K_DIAG_SW_PHEAR_ME 0x00800000 /* ??? */ /* * TSF (clock) register (lower 32 bits) -- cgit v1.2.3 From dc4769f0bb949e312ad8d9b652047ff6709978c2 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Tue, 28 Sep 2010 01:53:42 +0200 Subject: carl9170: interrupt urbs must not set URB_ZERO_PACKET MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch fixes a bug in the driver which was exposed by CONFIG_USB_DEBUG: "usb 1-1.6.3: BOGUS urb flags, 40 --> 0" The transfer flag "URB_ZERO_PACKET" is only valid for bulk urbs. Reported-by: André Erdmann Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/ath/carl9170/usb.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/wireless/ath/carl9170/usb.c b/drivers/net/wireless/ath/carl9170/usb.c index eb789a9e4f15..c7f6193934ea 100644 --- a/drivers/net/wireless/ath/carl9170/usb.c +++ b/drivers/net/wireless/ath/carl9170/usb.c @@ -606,8 +606,6 @@ int __carl9170_exec_cmd(struct ar9170 *ar, struct carl9170_cmd *cmd, AR9170_USB_EP_CMD), cmd, cmd->hdr.len + 4, carl9170_usb_cmd_complete, ar, 1); - urb->transfer_flags |= URB_ZERO_PACKET; - if (free_buf) urb->transfer_flags |= URB_FREE_BUFFER; -- cgit v1.2.3 From 93b05238027420978d785569f8c1aa4a6867bc13 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 28 Sep 2010 12:53:14 +0200 Subject: cfg80211: always set IBSS basic rates IBSS started from wireless extensions is currently missing basic rate configuration, fix this by moving the code to generate the default to the common code that gets invoked for both nl80211 and wext. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/wireless/ibss.c | 19 +++++++++++++++++++ net/wireless/nl80211.c | 17 ----------------- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index 27a8ce9343c3..8cb6e08373b9 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c @@ -88,6 +88,25 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, if (wdev->ssid_len) return -EALREADY; + if (!params->basic_rates) { + /* + * If no rates were explicitly configured, + * use the mandatory rate set for 11b or + * 11a for maximum compatibility. + */ + struct ieee80211_supported_band *sband = + rdev->wiphy.bands[params->channel->band]; + int j; + u32 flag = params->channel->band == IEEE80211_BAND_5GHZ ? + IEEE80211_RATE_MANDATORY_A : + IEEE80211_RATE_MANDATORY_B; + + for (j = 0; j < sband->n_bitrates; j++) { + if (sband->bitrates[j].flags & flag) + params->basic_rates |= BIT(j); + } + } + if (WARN_ON(wdev->connect_keys)) kfree(wdev->connect_keys); wdev->connect_keys = connkeys; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 4ff827e8c362..9c84825803ce 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -4119,23 +4119,6 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) goto out; } } - } else { - /* - * If no rates were explicitly configured, - * use the mandatory rate set for 11b or - * 11a for maximum compatibility. - */ - struct ieee80211_supported_band *sband = - wiphy->bands[ibss.channel->band]; - int j; - u32 flag = ibss.channel->band == IEEE80211_BAND_5GHZ ? - IEEE80211_RATE_MANDATORY_A : - IEEE80211_RATE_MANDATORY_B; - - for (j = 0; j < sband->n_bitrates; j++) { - if (sband->bitrates[j].flags & flag) - ibss.basic_rates |= BIT(j); - } } err = cfg80211_join_ibss(rdev, dev, &ibss, connkeys); -- cgit v1.2.3 From f2176d7240e4f455a6e007703c7512fbde926dc8 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Tue, 28 Sep 2010 14:39:32 +0300 Subject: mac80211: Fix WMM driver queue configuration The WMM parameter configuration function (ieee80211_sta_wmm_params) only configures the WMM parameters to the driver is the wmm_last_param_set counter value is changed by the AP. The wmm_last_param_set is initialized to -1 on association in order to ensure the configuration is made to the driver at least once on association, but currently this initialization is done *after* the WMM parameter configuration function was called. This leads to unreliability in the driver getting properly configured on first association (depending on what counter value the AP happens to use.) When disassociating (the wmm default parameters are configured to the driver) and then reassociating, due to the above the WMM configuration is not set to the driver at all. On drivers without beacon filtering the problem is corrected by later beacons, but on drivers with beacon filtering the WMM will remain permanently incorrectly configured. Fix this by moving the initialization of wmm_last_param_set to -1 before ieee80211_sta_wmm_params is called on association. Signed-off-by: Juuso Oikarinen Acked-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/mlme.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 8b733cf6f3ea..77913a15f537 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -880,14 +880,6 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, sdata->u.mgd.flags &= ~(IEEE80211_STA_CONNECTION_POLL | IEEE80211_STA_BEACON_POLL); - /* - * Always handle WMM once after association regardless - * of the first value the AP uses. Setting -1 here has - * that effect because the AP values is an unsigned - * 4-bit value. - */ - sdata->u.mgd.wmm_last_param_set = -1; - ieee80211_led_assoc(local, 1); if (local->hw.flags & IEEE80211_HW_NEED_DTIM_PERIOD) @@ -1367,6 +1359,14 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, return false; } + /* + * Always handle WMM once after association regardless + * of the first value the AP uses. Setting -1 here has + * that effect because the AP values is an unsigned + * 4-bit value. + */ + ifmgd->wmm_last_param_set = -1; + if (elems.wmm_param) ieee80211_sta_wmm_params(local, sdata, elems.wmm_param, elems.wmm_param_len); -- cgit v1.2.3