Dave, Please pull this batch of fixes intended for the 3.14 stream! For the mac80211 bits, Johannes says: "This is just a collection of small fixes, the commit logs explain the details. The only thing that isn't strictly a fix is the 5/10 MHz enabling, I had forgotten this and there's little point in waiting longer. The patch simply removes the force-disable code that I put in when there was a problem with the userspace API (that has long been fixed.)" For the iwlwifi bits, Emmanuel says: "I have an important fix that disables A band in case the driver thought it was enabled, and the firmware disagreed. We ended up making the firmware unhappy. I also fix the station table in AP mode and fix the scan while we have BT working. Johannes removes a static variable that could potentially lead to to issues on multi-device setups and disables scheduled scan to avoid issues with old versions of wpa_supplicant. A small fix from David on scan and a few new device IDs for 7265." On top of that... Oleksij Rempel adds a USB ID to the ar5523 driver and changes the default powersave setting for ath9k_htc to "off", due to observed stability issues (based on an equivalent ath9k patch). Stanislaw Gruszka similarly disables powersave for a couple of rt2x00 drivers. He also fixes a couple of scheduling while atomic issues in ath9k_htc. Sujith Manoharan rounds-out the powersave disables with one for ath9k. He also fixes a build prolem with ath9k on ARM and fixes an ath9k Tx power calculation. Finally, Andrea Merello fixes a couple of lingering DMA mapping problems in the rtl8180 driver. Please let me know if there are problems! Thanks, John --- The following changes since commit ee262ad827f89e2dc7851ec2986953b5b125c6bc: inet: defines IPPROTO_* needed for module alias generation (2014-02-06 21:18:06 -0800) are available in the git repository at: git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless.git for-davem for you to fetch changes up to 0f96b860bc5e97d4776d0cb375c7ca1f4864f9e9: Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless into for-davem (2014-02-07 13:44:14 -0500) ---------------------------------------------------------------- David Spinadel (1): iwlwifi: mvm: notify match found without filtering Eliad Peller (1): mac80211: move roc cookie assignment earlier Emmanuel Grumbach (6): iwlwifi: mvm: print the version of the firmware when it asserts iwlwifi: mvm: don't leak a station when we drain iwlwifi: mvm: BT Coex - disable BT when TXing probe request in scan iwlwifi: mvm: don't allow A band if SKU forbids it mac80211: avoid deadlock revealed by lockdep mac80211: release the channel in error path in start_ap Johannes Berg (7): iwlwifi: mvm: make local pointer non-static iwlwifi: mvm: disable scheduled scan cfg80211: re-enable 5/10 MHz support cfg80211: fix scan done race cfg80211: send scan results from work queue mac80211: fix fragmentation code, particularly for encryption mac80211: fix virtual monitor interface iteration John W. Linville (3): Merge branch 'for-john' of git://git.kernel.org/.../iwlwifi/iwlwifi-fixes Merge branch 'for-john' of git://git.kernel.org/.../jberg/mac80211 Merge branch 'master' of git://git.kernel.org/.../linville/wireless into for-davem Oleksij Rempel (2): ath9k_htc: Do not support PowerSave by default ar5523: fix usb id for Gigaset. Oren Givon (1): iwlwifi: add more 7265 HW IDs Pontus Fuchs (1): nl80211: Reset split_start when netlink skb is exhausted Stanislaw Gruszka (4): ath9k_htc: make ->sta_rc_update atomic for most calls rt2800: disable PS by default on USB rt2500: disable PS by default ath9k_htc: avoid scheduling while atomic on sta_rc_update Sujith Manoharan (4): ath9k: Fix build error on ARM ath9k: Do not support PowerSave by default ath9k: Fix TX power calculation mac80211: Fix IBSS disconnect andrea.merello (2): rtl8180: Add error check for pci_map_single return value in RX path rtl8180: Add error check for pci_map_single return value in TX path drivers/net/wireless/ath/ar5523/ar5523.c | 2 +- drivers/net/wireless/ath/ath9k/ar9003_eeprom.c | 4 ++ drivers/net/wireless/ath/ath9k/htc.h | 2 + drivers/net/wireless/ath/ath9k/htc_drv_init.c | 8 ++- drivers/net/wireless/ath/ath9k/htc_drv_main.c | 63 ++++++++++++++-------- drivers/net/wireless/ath/ath9k/hw.c | 5 +- drivers/net/wireless/ath/ath9k/init.c | 8 ++- drivers/net/wireless/iwlwifi/iwl-nvm-parse.c | 5 ++ drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h | 4 +- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 2 +- drivers/net/wireless/iwlwifi/mvm/scan.c | 5 +- drivers/net/wireless/iwlwifi/mvm/sta.c | 2 +- drivers/net/wireless/iwlwifi/mvm/tx.c | 73 +++++++++++++------------- drivers/net/wireless/iwlwifi/mvm/utils.c | 2 + drivers/net/wireless/iwlwifi/pcie/drv.c | 7 ++- drivers/net/wireless/rt2x00/rt2500pci.c | 5 ++ drivers/net/wireless/rt2x00/rt2500usb.c | 5 ++ drivers/net/wireless/rt2x00/rt2800lib.c | 5 +- drivers/net/wireless/rtl818x/rtl8180/dev.c | 23 ++++++-- net/mac80211/cfg.c | 44 ++++++++-------- net/mac80211/ht.c | 4 +- net/mac80211/ibss.c | 5 +- net/mac80211/iface.c | 27 +++++++--- net/mac80211/tx.c | 2 +- net/wireless/core.c | 17 +++--- net/wireless/core.h | 4 +- net/wireless/nl80211.c | 32 +++++------ net/wireless/nl80211.h | 8 +-- net/wireless/scan.c | 40 ++++++++------ net/wireless/sme.c | 2 +- 30 files changed, 256 insertions(+), 159 deletions(-) diff --git a/drivers/net/wireless/ath/ar5523/ar5523.c b/drivers/net/wireless/ath/ar5523/ar5523.c index 8aa20df55e50..507d9a9ee69a 100644 --- a/drivers/net/wireless/ath/ar5523/ar5523.c +++ b/drivers/net/wireless/ath/ar5523/ar5523.c @@ -1764,7 +1764,7 @@ static struct usb_device_id ar5523_id_table[] = { AR5523_DEVICE_UG(0x07d1, 0x3a07), /* D-Link / WUA-2340 rev A1 */ AR5523_DEVICE_UG(0x1690, 0x0712), /* Gigaset / AR5523 */ AR5523_DEVICE_UG(0x1690, 0x0710), /* Gigaset / SMCWUSBTG */ - AR5523_DEVICE_UG(0x129b, 0x160c), /* Gigaset / USB stick 108 + AR5523_DEVICE_UG(0x129b, 0x160b), /* Gigaset / USB stick 108 (CyberTAN Technology) */ AR5523_DEVICE_UG(0x16ab, 0x7801), /* Globalsun / AR5523_1 */ AR5523_DEVICE_UX(0x16ab, 0x7811), /* Globalsun / AR5523_2 */ diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index 25243cbc07f0..b8daff78b9d1 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -5065,6 +5065,10 @@ static u16 ar9003_hw_get_max_edge_power(struct ar9300_eeprom *eep, break; } } + + if (is2GHz && !twiceMaxEdgePower) + twiceMaxEdgePower = 60; + return twiceMaxEdgePower; } diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 58da3468d1f0..99a203174f45 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -262,6 +262,8 @@ enum tid_aggr_state { struct ath9k_htc_sta { u8 index; enum tid_aggr_state tid_state[ATH9K_HTC_MAX_TID]; + struct work_struct rc_update_work; + struct ath9k_htc_priv *htc_priv; }; #define ATH9K_HTC_RXBUF 256 diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index f4e1de20d99c..c57d6b859c04 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -34,6 +34,10 @@ static int ath9k_htc_btcoex_enable; module_param_named(btcoex_enable, ath9k_htc_btcoex_enable, int, 0444); MODULE_PARM_DESC(btcoex_enable, "Enable wifi-BT coexistence"); +static int ath9k_ps_enable; +module_param_named(ps_enable, ath9k_ps_enable, int, 0444); +MODULE_PARM_DESC(ps_enable, "Enable WLAN PowerSave"); + #define CHAN2G(_freq, _idx) { \ .center_freq = (_freq), \ .hw_value = (_idx), \ @@ -725,12 +729,14 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv, IEEE80211_HW_SPECTRUM_MGMT | IEEE80211_HW_HAS_RATE_CONTROL | IEEE80211_HW_RX_INCLUDES_FCS | - IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_PS_NULLFUNC_STACK | IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_MFP_CAPABLE | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING; + if (ath9k_ps_enable) + hw->flags |= IEEE80211_HW_SUPPORTS_PS; + hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC) | diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 608d739d1378..c9254a61ca52 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -1270,18 +1270,50 @@ static void ath9k_htc_configure_filter(struct ieee80211_hw *hw, mutex_unlock(&priv->mutex); } +static void ath9k_htc_sta_rc_update_work(struct work_struct *work) +{ + struct ath9k_htc_sta *ista = + container_of(work, struct ath9k_htc_sta, rc_update_work); + struct ieee80211_sta *sta = + container_of((void *)ista, struct ieee80211_sta, drv_priv); + struct ath9k_htc_priv *priv = ista->htc_priv; + struct ath_common *common = ath9k_hw_common(priv->ah); + struct ath9k_htc_target_rate trate; + + mutex_lock(&priv->mutex); + ath9k_htc_ps_wakeup(priv); + + memset(&trate, 0, sizeof(struct ath9k_htc_target_rate)); + ath9k_htc_setup_rate(priv, sta, &trate); + if (!ath9k_htc_send_rate_cmd(priv, &trate)) + ath_dbg(common, CONFIG, + "Supported rates for sta: %pM updated, rate caps: 0x%X\n", + sta->addr, be32_to_cpu(trate.capflags)); + else + ath_dbg(common, CONFIG, + "Unable to update supported rates for sta: %pM\n", + sta->addr); + + ath9k_htc_ps_restore(priv); + mutex_unlock(&priv->mutex); +} + static int ath9k_htc_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { struct ath9k_htc_priv *priv = hw->priv; + struct ath9k_htc_sta *ista = (struct ath9k_htc_sta *) sta->drv_priv; int ret; mutex_lock(&priv->mutex); ath9k_htc_ps_wakeup(priv); ret = ath9k_htc_add_station(priv, vif, sta); - if (!ret) + if (!ret) { + INIT_WORK(&ista->rc_update_work, ath9k_htc_sta_rc_update_work); + ista->htc_priv = priv; ath9k_htc_init_rate(priv, sta); + } ath9k_htc_ps_restore(priv); mutex_unlock(&priv->mutex); @@ -1293,12 +1325,13 @@ static int ath9k_htc_sta_remove(struct ieee80211_hw *hw, struct ieee80211_sta *sta) { struct ath9k_htc_priv *priv = hw->priv; - struct ath9k_htc_sta *ista; + struct ath9k_htc_sta *ista = (struct ath9k_htc_sta *) sta->drv_priv; int ret; + cancel_work_sync(&ista->rc_update_work); + mutex_lock(&priv->mutex); ath9k_htc_ps_wakeup(priv); - ista = (struct ath9k_htc_sta *) sta->drv_priv; htc_sta_drain(priv->htc, ista->index); ret = ath9k_htc_remove_station(priv, vif, sta); ath9k_htc_ps_restore(priv); @@ -1311,28 +1344,12 @@ static void ath9k_htc_sta_rc_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, u32 changed) { - struct ath9k_htc_priv *priv = hw->priv; - struct ath_common *common = ath9k_hw_common(priv->ah); - struct ath9k_htc_target_rate trate; - - mutex_lock(&priv->mutex); - ath9k_htc_ps_wakeup(priv); + struct ath9k_htc_sta *ista = (struct ath9k_htc_sta *) sta->drv_priv; - if (changed & IEEE80211_RC_SUPP_RATES_CHANGED) { - memset(&trate, 0, sizeof(struct ath9k_htc_target_rate)); - ath9k_htc_setup_rate(priv, sta, &trate); - if (!ath9k_htc_send_rate_cmd(priv, &trate)) - ath_dbg(common, CONFIG, - "Supported rates for sta: %pM updated, rate caps: 0x%X\n", - sta->addr, be32_to_cpu(trate.capflags)); - else - ath_dbg(common, CONFIG, - "Unable to update supported rates for sta: %pM\n", - sta->addr); - } + if (!(changed & IEEE80211_RC_SUPP_RATES_CHANGED)) + return; - ath9k_htc_ps_restore(priv); - mutex_unlock(&priv->mutex); + schedule_work(&ista->rc_update_work); } static int ath9k_htc_conf_tx(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index fbf43c05713f..11eab9f01fd8 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1316,7 +1316,7 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type) if (AR_SREV_9300_20_OR_LATER(ah)) udelay(50); else if (AR_SREV_9100(ah)) - udelay(10000); + mdelay(10); else udelay(100); @@ -2051,9 +2051,8 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah) REG_SET_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN); - if (AR_SREV_9100(ah)) - udelay(10000); + mdelay(10); else udelay(50); diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index c36de303c8f3..1fc2e5a26b52 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -57,6 +57,10 @@ static int ath9k_bt_ant_diversity; module_param_named(bt_ant_diversity, ath9k_bt_ant_diversity, int, 0444); MODULE_PARM_DESC(bt_ant_diversity, "Enable WLAN/BT RX antenna diversity"); +static int ath9k_ps_enable; +module_param_named(ps_enable, ath9k_ps_enable, int, 0444); +MODULE_PARM_DESC(ps_enable, "Enable WLAN PowerSave"); + bool is_ath9k_unloaded; /* We use the hw_value as an index into our private channel structure */ @@ -903,13 +907,15 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | IEEE80211_HW_SIGNAL_DBM | - IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_PS_NULLFUNC_STACK | IEEE80211_HW_SPECTRUM_MGMT | IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_SUPPORTS_RC_TABLE | IEEE80211_HW_SUPPORTS_HT_CCK_RATES; + if (ath9k_ps_enable) + hw->flags |= IEEE80211_HW_SUPPORTS_PS; + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) { hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION; diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c index f06f4cbe1317..725e954d8475 100644 --- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c @@ -182,6 +182,11 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, for (ch_idx = 0; ch_idx < IWL_NUM_CHANNELS; ch_idx++) { ch_flags = __le16_to_cpup(nvm_ch_flags + ch_idx); + + if (ch_idx >= NUM_2GHZ_CHANNELS && + !data->sku_cap_band_52GHz_enable) + ch_flags &= ~NVM_CHANNEL_VALID; + if (!(ch_flags & NVM_CHANNEL_VALID)) { IWL_DEBUG_EEPROM(dev, "Ch. %d Flags %x [%sGHz] - No traffic\n", diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h index 73cbba7424f2..9426905de6b2 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h @@ -504,6 +504,7 @@ struct iwl_scan_offload_profile { * @match_notify: clients waiting for match found notification * @pass_match: clients waiting for the results * @active_clients: active clients bitmap - enum scan_framework_client + * @any_beacon_notify: clients waiting for match notification without match */ struct iwl_scan_offload_profile_cfg { struct iwl_scan_offload_profile profiles[IWL_SCAN_MAX_PROFILES]; @@ -512,7 +513,8 @@ struct iwl_scan_offload_profile_cfg { u8 match_notify; u8 pass_match; u8 active_clients; - u8 reserved[3]; + u8 any_beacon_notify; + u8 reserved[2]; } __packed; /** diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index c49b5073c251..6bf9766e5982 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -246,7 +246,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) else hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; - if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_SCHED_SCAN) { + if (0 && mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_SCHED_SCAN) { hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; hw->wiphy->max_sched_scan_ssids = PROBE_OPTION_MAX; hw->wiphy->max_match_sets = IWL_SCAN_MAX_PROFILES; diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index 0e0007960612..742afc429c94 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -344,7 +344,8 @@ int iwl_mvm_scan_request(struct iwl_mvm *mvm, iwl_mvm_scan_fill_ssids(cmd, req, basic_ssid ? 1 : 0); - cmd->tx_cmd.tx_flags = cpu_to_le32(TX_CMD_FLG_SEQ_CTL); + cmd->tx_cmd.tx_flags = cpu_to_le32(TX_CMD_FLG_SEQ_CTL | + TX_CMD_FLG_BT_DIS); cmd->tx_cmd.sta_id = mvm->aux_sta.sta_id; cmd->tx_cmd.life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE); cmd->tx_cmd.rate_n_flags = @@ -807,6 +808,8 @@ int iwl_mvm_config_sched_scan_profiles(struct iwl_mvm *mvm, profile_cfg->active_clients = SCAN_CLIENT_SCHED_SCAN; profile_cfg->pass_match = SCAN_CLIENT_SCHED_SCAN; profile_cfg->match_notify = SCAN_CLIENT_SCHED_SCAN; + if (!req->n_match_sets || !req->match_sets[0].ssid.ssid_len) + profile_cfg->any_beacon_notify = SCAN_CLIENT_SCHED_SCAN; for (i = 0; i < req->n_match_sets; i++) { profile = &profile_cfg->profiles[i]; diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index ec1812133235..3397f59cd4e4 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c @@ -652,7 +652,7 @@ int iwl_mvm_send_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); static const u8 _baddr[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; - static const u8 *baddr = _baddr; + const u8 *baddr = _baddr; lockdep_assert_held(&mvm->mutex); diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index 90378c217bc7..4df12fa9d336 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c @@ -659,8 +659,14 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, rcu_read_lock(); sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]); + /* + * sta can't be NULL otherwise it'd mean that the sta has been freed in + * the firmware while we still have packets for it in the Tx queues. + */ + if (WARN_ON_ONCE(!sta)) + goto out; - if (!IS_ERR_OR_NULL(sta)) { + if (!IS_ERR(sta)) { mvmsta = iwl_mvm_sta_from_mac80211(sta); if (tid != IWL_TID_NON_QOS) { @@ -675,7 +681,6 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, spin_unlock_bh(&mvmsta->lock); } } else { - sta = NULL; mvmsta = NULL; } @@ -683,42 +688,38 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, * If the txq is not an AMPDU queue, there is no chance we freed * several skbs. Check that out... */ - if (txq_id < mvm->first_agg_queue && !WARN_ON(skb_freed > 1) && - atomic_sub_and_test(skb_freed, &mvm->pending_frames[sta_id])) { - if (mvmsta) { - /* - * If there are no pending frames for this STA, notify - * mac80211 that this station can go to sleep in its - * STA table. - */ - if (mvmsta->vif->type == NL80211_IFTYPE_AP) - ieee80211_sta_block_awake(mvm->hw, sta, false); - /* - * We might very well have taken mvmsta pointer while - * the station was being removed. The remove flow might - * have seen a pending_frame (because we didn't take - * the lock) even if now the queues are drained. So make - * really sure now that this the station is not being - * removed. If it is, run the drain worker to remove it. - */ - spin_lock_bh(&mvmsta->lock); - sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]); - if (!sta || PTR_ERR(sta) == -EBUSY) { - /* - * Station disappeared in the meantime: - * so we are draining. - */ - set_bit(sta_id, mvm->sta_drained); - schedule_work(&mvm->sta_drained_wk); - } - spin_unlock_bh(&mvmsta->lock); - } else if (!mvmsta && PTR_ERR(sta) == -EBUSY) { - /* Tx response without STA, so we are draining */ - set_bit(sta_id, mvm->sta_drained); - schedule_work(&mvm->sta_drained_wk); - } + if (txq_id >= mvm->first_agg_queue) + goto out; + + /* We can't free more than one frame at once on a shared queue */ + WARN_ON(skb_freed > 1); + + /* If we have still frames from this STA nothing to do here */ + if (!atomic_sub_and_test(skb_freed, &mvm->pending_frames[sta_id])) + goto out; + + if (mvmsta && mvmsta->vif->type == NL80211_IFTYPE_AP) { + /* + * If there are no pending frames for this STA, notify + * mac80211 that this station can go to sleep in its + * STA table. + * If mvmsta is not NULL, sta is valid. + */ + ieee80211_sta_block_awake(mvm->hw, sta, false); + } + + if (PTR_ERR(sta) == -EBUSY || PTR_ERR(sta) == -ENOENT) { + /* + * We are draining and this was the last packet - pre_rcu_remove + * has been called already. We might be after the + * synchronize_net already. + * Don't rely on iwl_mvm_rm_sta to see the empty Tx queues. + */ + set_bit(sta_id, mvm->sta_drained); + schedule_work(&mvm->sta_drained_wk); } +out: rcu_read_unlock(); } diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c index a4a5e25623c3..86989df69356 100644 --- a/drivers/net/wireless/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/iwlwifi/mvm/utils.c @@ -411,6 +411,8 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm) mvm->status, table.valid); } + IWL_ERR(mvm, "Loaded firmware version: %s\n", mvm->fw->fw_version); + trace_iwlwifi_dev_ucode_error(trans->dev, table.error_id, table.tsf_low, table.data1, table.data2, table.data3, table.blink1, table.blink2, table.ilink1, diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c index 3040924f5f3c..f47bcbe2945a 100644 --- a/drivers/net/wireless/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/iwlwifi/pcie/drv.c @@ -359,20 +359,25 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = { /* 7265 Series */ {IWL_PCI_DEVICE(0x095A, 0x5010, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x5110, iwl7265_2ac_cfg)}, + {IWL_PCI_DEVICE(0x095A, 0x5112, iwl7265_2ac_cfg)}, + {IWL_PCI_DEVICE(0x095A, 0x5100, iwl7265_2ac_cfg)}, + {IWL_PCI_DEVICE(0x095A, 0x510A, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095B, 0x5310, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095B, 0x5302, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095B, 0x5210, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x5012, iwl7265_2ac_cfg)}, - {IWL_PCI_DEVICE(0x095A, 0x500A, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x5410, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x5400, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x1010, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x5000, iwl7265_2n_cfg)}, + {IWL_PCI_DEVICE(0x095A, 0x500A, iwl7265_2n_cfg)}, {IWL_PCI_DEVICE(0x095B, 0x5200, iwl7265_2n_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x5002, iwl7265_n_cfg)}, {IWL_PCI_DEVICE(0x095B, 0x5202, iwl7265_n_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x9010, iwl7265_2ac_cfg)}, + {IWL_PCI_DEVICE(0x095A, 0x9012, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x9110, iwl7265_2ac_cfg)}, + {IWL_PCI_DEVICE(0x095A, 0x9112, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x9210, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x9510, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x9310, iwl7265_2ac_cfg)}, diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index abc5f56f29fe..2f1cd929c6f6 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1877,6 +1877,11 @@ static int rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) EEPROM_MAC_ADDR_0)); /* + * Disable powersaving as default. + */ + rt2x00dev->hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; + + /* * Initialize hw_mode information. */ spec->supported_bands = SUPPORT_BAND_2GHZ; diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 9f16824cd1bc..d849d590de25 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1706,6 +1706,11 @@ static int rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_PS_NULLFUNC_STACK; + /* + * Disable powersaving as default. + */ + rt2x00dev->hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; + SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev); SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, rt2x00_eeprom_addr(rt2x00dev, diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index b8f5b06006c4..7f8b5d156c8c 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -7458,10 +7458,9 @@ static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev) u32 reg; /* - * Disable powersaving as default on PCI devices. + * Disable powersaving as default. */ - if (rt2x00_is_pci(rt2x00dev) || rt2x00_is_soc(rt2x00dev)) - rt2x00dev->hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; + rt2x00dev->hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; /* * Initialize all hw fields. diff --git a/drivers/net/wireless/rtl818x/rtl8180/dev.c b/drivers/net/wireless/rtl818x/rtl8180/dev.c index 8ec17aad0e52..3867d1470b36 100644 --- a/drivers/net/wireless/rtl818x/rtl8180/dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180/dev.c @@ -107,6 +107,7 @@ static void rtl8180_handle_rx(struct ieee80211_hw *dev) struct rtl8180_priv *priv = dev->priv; unsigned int count = 32; u8 signal, agc, sq; + dma_addr_t mapping; while (count--) { struct rtl8180_rx_desc *entry = &priv->rx_ring[priv->rx_idx]; @@ -128,6 +129,17 @@ static void rtl8180_handle_rx(struct ieee80211_hw *dev) if (unlikely(!new_skb)) goto done; + mapping = pci_map_single(priv->pdev, + skb_tail_pointer(new_skb), + MAX_RX_SIZE, PCI_DMA_FROMDEVICE); + + if (pci_dma_mapping_error(priv->pdev, mapping)) { + kfree_skb(new_skb); + dev_err(&priv->pdev->dev, "RX DMA map error\n"); + + goto done; + } + pci_unmap_single(priv->pdev, *((dma_addr_t *)skb->cb), MAX_RX_SIZE, PCI_DMA_FROMDEVICE); @@ -158,9 +170,7 @@ static void rtl8180_handle_rx(struct ieee80211_hw *dev) skb = new_skb; priv->rx_buf[priv->rx_idx] = skb; - *((dma_addr_t *) skb->cb) = - pci_map_single(priv->pdev, skb_tail_pointer(skb), - MAX_RX_SIZE, PCI_DMA_FROMDEVICE); + *((dma_addr_t *) skb->cb) = mapping; } done: @@ -266,6 +276,13 @@ static void rtl8180_tx(struct ieee80211_hw *dev, mapping = pci_map_single(priv->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); + if (pci_dma_mapping_error(priv->pdev, mapping)) { + kfree_skb(skb); + dev_err(&priv->pdev->dev, "TX DMA mapping error\n"); + return; + + } + tx_flags = RTL818X_TX_DESC_FLAG_OWN | RTL818X_TX_DESC_FLAG_FS | RTL818X_TX_DESC_FLAG_LS | (ieee80211_get_tx_rate(dev, info)->hw_value << 24) | diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index f9ae9b85d4c1..453e974287d1 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1021,8 +1021,10 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, IEEE80211_P2P_OPPPS_ENABLE_BIT; err = ieee80211_assign_beacon(sdata, ¶ms->beacon); - if (err < 0) + if (err < 0) { + ieee80211_vif_release_channel(sdata); return err; + } changed |= err; err = drv_start_ap(sdata->local, sdata); @@ -1032,6 +1034,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, if (old) kfree_rcu(old, rcu_head); RCU_INIT_POINTER(sdata->u.ap.beacon, NULL); + ieee80211_vif_release_channel(sdata); return err; } @@ -1090,8 +1093,6 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) kfree(sdata->u.ap.next_beacon); sdata->u.ap.next_beacon = NULL; - cancel_work_sync(&sdata->u.ap.request_smps_work); - /* turn off carrier for this interface and dependent VLANs */ list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) netif_carrier_off(vlan->dev); @@ -1103,6 +1104,7 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) kfree_rcu(old_beacon, rcu_head); if (old_probe_resp) kfree_rcu(old_probe_resp, rcu_head); + sdata->u.ap.driver_smps_mode = IEEE80211_SMPS_OFF; __sta_info_flush(sdata, true); ieee80211_free_keys(sdata, true); @@ -2638,6 +2640,24 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local, INIT_DELAYED_WORK(&roc->work, ieee80211_sw_roc_work); INIT_LIST_HEAD(&roc->dependents); + /* + * cookie is either the roc cookie (for normal roc) + * or the SKB (for mgmt TX) + */ + if (!txskb) { + /* local->mtx protects this */ + local->roc_cookie_counter++; + roc->cookie = local->roc_cookie_counter; + /* wow, you wrapped 64 bits ... more likely a bug */ + if (WARN_ON(roc->cookie == 0)) { + roc->cookie = 1; + local->roc_cookie_counter++; + } + *cookie = roc->cookie; + } else { + *cookie = (unsigned long)txskb; + } + /* if there's one pending or we're scanning, queue this one */ if (!list_empty(&local->roc_list) || local->scanning || local->radar_detect_enabled) @@ -2772,24 +2792,6 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local, if (!queued) list_add_tail(&roc->list, &local->roc_list); - /* - * cookie is either the roc cookie (for normal roc) - * or the SKB (for mgmt TX) - */ - if (!txskb) { - /* local->mtx protects this */ - local->roc_cookie_counter++; - roc->cookie = local->roc_cookie_counter; - /* wow, you wrapped 64 bits ... more likely a bug */ - if (WARN_ON(roc->cookie == 0)) { - roc->cookie = 1; - local->roc_cookie_counter++; - } - *cookie = roc->cookie; - } else { - *cookie = (unsigned long)txskb; - } - return 0; } diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index fab7b91923e0..70dd013de836 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c @@ -466,7 +466,9 @@ void ieee80211_request_smps_ap_work(struct work_struct *work) u.ap.request_smps_work); sdata_lock(sdata); - __ieee80211_request_smps_ap(sdata, sdata->u.ap.driver_smps_mode); + if (sdata_dereference(sdata->u.ap.beacon, sdata)) + __ieee80211_request_smps_ap(sdata, + sdata->u.ap.driver_smps_mode); sdata_unlock(sdata); } diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 771080ec7212..2796a198728f 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -695,12 +695,9 @@ static void ieee80211_ibss_disconnect(struct ieee80211_sub_if_data *sdata) struct cfg80211_bss *cbss; struct beacon_data *presp; struct sta_info *sta; - int active_ibss; u16 capability; - active_ibss = ieee80211_sta_active_ibss(sdata); - - if (!active_ibss && !is_zero_ether_addr(ifibss->bssid)) { + if (!is_zero_ether_addr(ifibss->bssid)) { capability = WLAN_CAPABILITY_IBSS; if (ifibss->privacy) diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 3dfd20a453ab..d6d1f1df9119 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -418,20 +418,24 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local) return ret; } + mutex_lock(&local->iflist_mtx); + rcu_assign_pointer(local->monitor_sdata, sdata); + mutex_unlock(&local->iflist_mtx); + mutex_lock(&local->mtx); ret = ieee80211_vif_use_channel(sdata, &local->monitor_chandef, IEEE80211_CHANCTX_EXCLUSIVE); mutex_unlock(&local->mtx); if (ret) { + mutex_lock(&local->iflist_mtx); + rcu_assign_pointer(local->monitor_sdata, NULL); + mutex_unlock(&local->iflist_mtx); + synchronize_net(); drv_remove_interface(local, sdata); kfree(sdata); return ret; } - mutex_lock(&local->iflist_mtx); - rcu_assign_pointer(local->monitor_sdata, sdata); - mutex_unlock(&local->iflist_mtx); - return 0; } @@ -770,12 +774,19 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, ieee80211_roc_purge(local, sdata); - if (sdata->vif.type == NL80211_IFTYPE_STATION) + switch (sdata->vif.type) { + case NL80211_IFTYPE_STATION: ieee80211_mgd_stop(sdata); - - if (sdata->vif.type == NL80211_IFTYPE_ADHOC) + break; + case NL80211_IFTYPE_ADHOC: ieee80211_ibss_stop(sdata); - + break; + case NL80211_IFTYPE_AP: + cancel_work_sync(&sdata->u.ap.request_smps_work); + break; + default: + break; + } /* * Remove all stations associated with this interface. diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 27c990bf2320..97a02d3f7d87 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -878,7 +878,7 @@ static int ieee80211_fragment(struct ieee80211_tx_data *tx, } /* adjust first fragment's length */ - skb->len = hdrlen + per_fragm; + skb_trim(skb, hdrlen + per_fragm); return 0; } diff --git a/net/wireless/core.c b/net/wireless/core.c index d89dee2259b5..010892b81a06 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -203,8 +203,11 @@ void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev, rdev->opencount--; - WARN_ON(rdev->scan_req && rdev->scan_req->wdev == wdev && - !rdev->scan_req->notified); + if (rdev->scan_req && rdev->scan_req->wdev == wdev) { + if (WARN_ON(!rdev->scan_req->notified)) + rdev->scan_req->aborted = true; + ___cfg80211_scan_done(rdev, false); + } } static int cfg80211_rfkill_set_block(void *data, bool blocked) @@ -440,9 +443,6 @@ int wiphy_register(struct wiphy *wiphy) int i; u16 ifmodes = wiphy->interface_modes; - /* support for 5/10 MHz is broken due to nl80211 API mess - disable */ - wiphy->flags &= ~WIPHY_FLAG_SUPPORTS_5_10_MHZ; - /* * There are major locking problems in nl80211/mac80211 for CSA, * disable for all drivers until this has been reworked. @@ -859,8 +859,11 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, break; case NETDEV_DOWN: cfg80211_update_iface_num(rdev, wdev->iftype, -1); - WARN_ON(rdev->scan_req && rdev->scan_req->wdev == wdev && - !rdev->scan_req->notified); + if (rdev->scan_req && rdev->scan_req->wdev == wdev) { + if (WARN_ON(!rdev->scan_req->notified)) + rdev->scan_req->aborted = true; + ___cfg80211_scan_done(rdev, false); + } if (WARN_ON(rdev->sched_scan_req && rdev->sched_scan_req->dev == wdev->netdev)) { diff --git a/net/wireless/core.h b/net/wireless/core.h index 37ec16d7bb1a..f1d193b557b6 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -62,6 +62,7 @@ struct cfg80211_registered_device { struct rb_root bss_tree; u32 bss_generation; struct cfg80211_scan_request *scan_req; /* protected by RTNL */ + struct sk_buff *scan_msg; struct cfg80211_sched_scan_request *sched_scan_req; unsigned long suspend_at; struct work_struct scan_done_wk; @@ -361,7 +362,8 @@ int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, struct key_params *params, int key_idx, bool pairwise, const u8 *mac_addr); void __cfg80211_scan_done(struct work_struct *wk); -void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev); +void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, + bool send_message); void __cfg80211_sched_scan_results(struct work_struct *wk); int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev, bool driver_initiated); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 7a742594916e..4fe2e6e2bc76 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -1719,9 +1719,10 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb) * We can then retry with the larger buffer. */ if ((ret == -ENOBUFS || ret == -EMSGSIZE) && - !skb->len && + !skb->len && !state->split && cb->min_dump_alloc < 4096) { cb->min_dump_alloc = 4096; + state->split_start = 0; rtnl_unlock(); return 1; } @@ -5244,7 +5245,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) if (!rdev->ops->scan) return -EOPNOTSUPP; - if (rdev->scan_req) { + if (rdev->scan_req || rdev->scan_msg) { err = -EBUSY; goto unlock; } @@ -10011,40 +10012,31 @@ void nl80211_send_scan_start(struct cfg80211_registered_device *rdev, NL80211_MCGRP_SCAN, GFP_KERNEL); } -void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, - struct wireless_dev *wdev) +struct sk_buff *nl80211_build_scan_msg(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev, bool aborted) { struct sk_buff *msg; msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!msg) - return; + return NULL; if (nl80211_send_scan_msg(msg, rdev, wdev, 0, 0, 0, - NL80211_CMD_NEW_SCAN_RESULTS) < 0) { + aborted ? NL80211_CMD_SCAN_ABORTED : + NL80211_CMD_NEW_SCAN_RESULTS) < 0) { nlmsg_free(msg); - return; + return NULL; } - genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, - NL80211_MCGRP_SCAN, GFP_KERNEL); + return msg; } -void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, - struct wireless_dev *wdev) +void nl80211_send_scan_result(struct cfg80211_registered_device *rdev, + struct sk_buff *msg) { - struct sk_buff *msg; - - msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!msg) return; - if (nl80211_send_scan_msg(msg, rdev, wdev, 0, 0, 0, - NL80211_CMD_SCAN_ABORTED) < 0) { - nlmsg_free(msg); - return; - } - genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, NL80211_MCGRP_SCAN, GFP_KERNEL); } diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index b1b231324e10..75799746d845 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h @@ -8,10 +8,10 @@ void nl80211_exit(void); void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev); void nl80211_send_scan_start(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev); -void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, - struct wireless_dev *wdev); -void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, - struct wireless_dev *wdev); +struct sk_buff *nl80211_build_scan_msg(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev, bool aborted); +void nl80211_send_scan_result(struct cfg80211_registered_device *rdev, + struct sk_buff *msg); void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev, struct net_device *netdev, u32 cmd); void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev, diff --git a/net/wireless/scan.c b/net/wireless/scan.c index b528e31da2cf..d1ed4aebbbb7 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -161,18 +161,25 @@ static void __cfg80211_bss_expire(struct cfg80211_registered_device *dev, dev->bss_generation++; } -void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev) +void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, + bool send_message) { struct cfg80211_scan_request *request; struct wireless_dev *wdev; + struct sk_buff *msg; #ifdef CONFIG_CFG80211_WEXT union iwreq_data wrqu; #endif ASSERT_RTNL(); - request = rdev->scan_req; + if (rdev->scan_msg) { + nl80211_send_scan_result(rdev, rdev->scan_msg); + rdev->scan_msg = NULL; + return; + } + request = rdev->scan_req; if (!request) return; @@ -186,18 +193,16 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev) if (wdev->netdev) cfg80211_sme_scan_done(wdev->netdev); - if (request->aborted) { - nl80211_send_scan_aborted(rdev, wdev); - } else { - if (request->flags & NL80211_SCAN_FLAG_FLUSH) { - /* flush entries from previous scans */ - spin_lock_bh(&rdev->bss_lock); - __cfg80211_bss_expire(rdev, request->scan_start); - spin_unlock_bh(&rdev->bss_lock); - } - nl80211_send_scan_done(rdev, wdev); + if (!request->aborted && + request->flags & NL80211_SCAN_FLAG_FLUSH) { + /* flush entries from previous scans */ + spin_lock_bh(&rdev->bss_lock); + __cfg80211_bss_expire(rdev, request->scan_start); + spin_unlock_bh(&rdev->bss_lock); } + msg = nl80211_build_scan_msg(rdev, wdev, request->aborted); + #ifdef CONFIG_CFG80211_WEXT if (wdev->netdev && !request->aborted) { memset(&wrqu, 0, sizeof(wrqu)); @@ -211,6 +216,11 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev) rdev->scan_req = NULL; kfree(request); + + if (!send_message) + rdev->scan_msg = msg; + else + nl80211_send_scan_result(rdev, msg); } void __cfg80211_scan_done(struct work_struct *wk) @@ -221,7 +231,7 @@ void __cfg80211_scan_done(struct work_struct *wk) scan_done_wk); rtnl_lock(); - ___cfg80211_scan_done(rdev); + ___cfg80211_scan_done(rdev, true); rtnl_unlock(); } @@ -1079,7 +1089,7 @@ int cfg80211_wext_siwscan(struct net_device *dev, if (IS_ERR(rdev)) return PTR_ERR(rdev); - if (rdev->scan_req) { + if (rdev->scan_req || rdev->scan_msg) { err = -EBUSY; goto out; } @@ -1481,7 +1491,7 @@ int cfg80211_wext_giwscan(struct net_device *dev, if (IS_ERR(rdev)) return PTR_ERR(rdev); - if (rdev->scan_req) + if (rdev->scan_req || rdev->scan_msg) return -EAGAIN; res = ieee80211_scan_results(rdev, info, extra, data->length); diff --git a/net/wireless/sme.c b/net/wireless/sme.c index a63509118508..f04d4c32e96e 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -67,7 +67,7 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev) ASSERT_RDEV_LOCK(rdev); ASSERT_WDEV_LOCK(wdev); - if (rdev->scan_req) + if (rdev->scan_req || rdev->scan_msg) return -EBUSY; if (wdev->conn->params.channel) -- John W. Linville Someday the world will need a hero, and you linville@xxxxxxxxxxxxx might be all we have. Be ready.
Attachment:
pgpi3t583BY9L.pgp
Description: PGP signature